我有一个 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流平图是一个也许的方法。所以关键的一点是不仅要重映射这个,还要用一个性能最强的方式来做这个。
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}]
你可以用这样的方法 groupingBy
和 Collector.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.flatMapping
从 Java 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());
您可以使用一定数量的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
.可以按以下方式进行。
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}