Java 8流将一个List<Map<>>通过相同的<Key,Value>分组到一个新的List<Map<>&gt。

问题描述 投票:0回答:2

我有一个 List<Map<String,String>>

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 LOOP解决了这个问题,但是当列表大小达到50000左右时,应用程序就会挂掉,所以我寻求一种性能更好的方法来解决这个问题。据我所知,Java 8流平图是一个也许的方法。所以关键的一点是不仅要重映射这个,还要用一个性能最强的方式来做这个。

java java-stream collectors groupingby
2个回答
7
投票
beforee.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}]

3
投票

你可以用这样的方法 groupingByCollector.of

List<Map<String, String>> list = new ArrayList<>(before.stream()
        .collect(Collectors.groupingBy(
                k -> k.get("date"),
                Collector.of( HashMap<String,String>::new,
                        (m,e)-> m.putAll(e),
                        (map1,map2)->{ map1.putAll(map2); return map1;}
                ))).values());

在这里,先用 Collectors.groupingBy 按日期分组。然后使用 Collector.of 领取 List<Map<String, String>> 变成 Map<String, String>. 使用地图值创建列表后。

并使用 Collectors.flatMappingJava 9

List<Map<String, String>> list = new ArrayList<>(before.stream()
        .collect(Collectors.groupingBy(
                k -> k.get("date"),
                Collectors.flatMapping(m -> m.entrySet().stream(), 
                    Collectors.toMap(k -> k.getKey(), v -> v.getValue(), (a,b) -> a))))
               .values());

1
投票

您可以使用一定数量的Collector,有序地达到非常相同的效果。

  • Collectors.groupingBy 按日期分组
  • Collectors.reducing 合并 Map<String, String> 物品
  • Collectors.collectingAndThen 的值进行转换,从 Map<String, Optional<Map<String, String>>>由于前者被还原为最终产出,所以 List<Map<String, String>>.
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())));

list 含有你要找的东西。

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

重要的是 这个方案有两个缺点:

  • 它看起来很笨拙,而且对于一个独立的观察者来说可能并不清楚。
  • 它将原始地图变异(修改),包含在 List<Map<String, String>> before.

0
投票

可以按以下方式进行。

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}
© www.soinside.com 2019 - 2024. All rights reserved.