提问者:小点点

Java 8通过相同的<键,值>将列表<map<>>流分组到新列表<map<>>


我有一个列表>,例如:

Map<String, String> m1 = new HashMap<>();
m1.put("date", "2020.1.5");
m1.put("B", "10");

Map<String, String> m2 = new HashMap<>();
m2.put("date", "2020.1.5");
m2.put("A", "20");

Map<String, String> m3 = new HashMap<>();
m3.put("date", "2020.1.6");
m3.put("A", "30");

Map<String, String> m4 = new HashMap<>();
m4.put("date", "2020.1.7");
m4.put("C", "30");

List<Map<String, String>> before = new ArrayList<>();
before.add(m1);
before.add(m2);
before.add(m3);
before.add(m4);

我的预期结果是生成一个新的列表映射,它按日期分组,并且在相同日期中设置的所有条目将被放在一起,如:

[{"A":"20","B":"10","date":"2020.1.5"},{"A":"30","date":"2020.1.6"},{"C":"30","date":"2020.1.7"}]

我尝试了下面的方法,但总是没有达到我预期的结果。

stream().flatmap().collect(Collectors.groupingBy())

此问题的一些附加注释:

我用for循环解决了这个问题,但是当列表大小为50000左右时,应用程序会挂起,所以我寻求一种性能更好的方法来实现这一点。 据我所知,Java 8溪流平原地图也许是一条路。 因此,关键的一点不仅是重新映射,而且是用一种性能最好的方法来实现这一点。


共3个答案

匿名用户

before
  .stream()
  .collect(Collectors.toMap((m) -> m.get("date"), m -> m, (a,b) -> {
      Map<String, String> res = new HashMap<>();
      res.putAll(a);
      res.putAll(b);
      return res;
  }))
  .values();

这就是你要找的解决方案。

tomap函数接收3个参数:

  • 密钥映射器,在您的示例中是日期
  • 值映射器,它是正在处理的映射本身
  • 合并函数,该函数获取具有相同日期的2个地图并将所有键放在一起

输出:

[{date=2020.1.5, A=20, B=10}, {date=2020.1.6, A=30}, {date=2020.1.7, C=30}]

匿名用户

您可以使用一定数量的收集器按顺序实现同样的结果:

  • Collectors.GroupingBy按日期分组
  • 收集器。减少以合并映射
  • Collectors.CollectingandThen将值从Map>转换为最终输出List>
List<Map<String, String>> list = before.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.groupingBy(
            m -> m.get("date"),
            Collectors.reducing((l, r) -> {
                l.putAll(r);
                return l; })
        ),
        o -> o.values().stream()
                       .flatMap(Optional::stream)
                       .collect(Collectors.toList())));

列表包含您要查找的内容:

[{date=2020.1.5,a=20,b=10},{date=2020.1.6,a=30},{date=2020.1.7,c=30}]

重要提示:此解决方案有两个缺点:

  • 看起来很笨拙,对于独立的查看者可能不清楚
  • 它改变(修改)包含在列表>中的原始映射; 之前。

匿名用户

可以这样做:

List<Map<String, String>> remapped = before.stream()
    .collect(Collectors.groupingBy(m -> m.get("date")))
    .values().stream()
    .map(e -> e.stream()
               .flatMap(m -> m.entrySet().stream())
               .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (x1, x2) -> x1)))
    .collect(Collectors.toList());

remapped.forEach(System.out::println);

输出:

{date=2020.1.5, A=20, B=10}
{date=2020.1.6, A=30}
{date=2020.1.7, C=30}