使用java 8流运算符将两个级别映射的列表减少为单个两级映射

时间:2016-01-04 20:02:44

标签: java lambda java-8 java-stream

我有一个嵌套地图列表(List<Map<String, Map<String, Long>>>),目标是将列表缩减为单个地图,合并将按如下方式进行:如果map1包含{{1 }}和x->{y->10, z->20}包含map2,然后这两个应合并到x->{y->20, z->20}

我尝试按照以下方式执行此操作,但这很正常。

x->{y->30, z->40}

还有其他更好更有效的方法来解决这个问题吗?

如果嵌套级别超过2,如何更干净地完成?假设列表与import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.function.BinaryOperator; import java.util.stream.Collectors; public class Test { public static void main(String args[]) throws IOException { Map<String, Map<String, Long>> data1 = new HashMap<>(); Map<String, Long> innerData1 = new HashMap<>(); innerData1.put("a", 10L); innerData1.put("b", 20L); data1.put("x", innerData1); Map<String, Long> innerData2 = new HashMap<>(); innerData2.put("b", 20L); innerData2.put("a", 10L); data1.put("x", innerData1); Map<String, Map<String, Long>> data2 = new HashMap<>(); data2.put("x", innerData2); List<Map<String, Map<String, Long>>> mapLists = new ArrayList<>(); mapLists.add(data1); mapLists.add(data2); Map<String, Map<String, Long>> result = mapLists.stream().flatMap(map -> map.entrySet().stream()). collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, new BinaryOperator<Map<String, Long>>() { @Override public Map<String, Long> apply(Map<String, Long> t, Map<String, Long> u) { Map<String, Long> result = t; for(Entry<String, Long> entry: u.entrySet()) { Long val = t.getOrDefault(entry.getKey(), 0L); result.put(entry.getKey(), val + entry.getValue()); } return result; } })); } } 类似,我们必须将其减少为单个List<Map<String, Map<String, Map<String, Long>>>>,假设具有与上述类似的合并功能。

2 个答案:

答案 0 :(得分:3)

您有一般的想法,可以简化将两个地图合并在一起的过程。 Merging the two maps can be done easily with

Map<String, Integer> mx = new HashMap<>(m1);
m2.forEach((k, v) -> mx.merge(k, v, Long::sum));

此代码从mx创建合并后的地图m1,然后迭代第二个地图m2的所有条目,并在mx的帮助下将每个条目合并到Map<String, Map<String, Long>> result = mapLists.stream() .flatMap(m -> m.entrySet().stream()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (m1, m2) -> { Map<String, Long> mx = new HashMap<>(m1); m2.forEach((k, v) -> mx.merge(k, v, Long::sum)); return mx; } )); {3}}:如果该键不存在映射,则此方法将使用给定值添加给定键,否则它将使用给定的重新映射函数重新映射该键的现有值和给定值。在我们的例子中,重映射函数应该将两个值相加。

代码:

merge

如果有更多“级别”,您可以定义private static <K, V> Map<K, V> merge(Map<K, V> m1, Map<K, V> m2, BiFunction<? super V, ? super V, ? extends V> remappingFunction) { Map<K, V> mx = new HashMap<>(m1); m2.forEach((k, v) -> mx.merge(k, v, remappingFunction)); return mx; } 方法:

Map<String, Map<String, Long>>

并递归使用它。例如,要合并两个m1 m2merge(m1, m2, (a, b) -> merge(a, b, Long::sum)); ,您可以使用

Collectors.toMap

因为重新映射功能是invisible(text(getSpPPolygonsLabptSlots(PA), labels=as.character(PA$NAME_1), cex=0.5))

答案 1 :(得分:2)

使用我的StreamEx库:

Map<String, Map<String, Long>> result = StreamEx.of(mapLists)
        .flatMapToEntry(m -> m)
        .toMap((m1, m2) -> EntryStream.of(m1).append(m2).toMap(Long::sum));

flatMapToEntry中间操作将地图展平为扩展EntryStream<String, Map<String, Long>>的{​​{1}}。 toMap终端操作只是使用提供的合并功能从条目流创建一个映射。要合并两张地图,我们再次使用Stream<Map.Entry<String, Map<String, Long>>>