使用java8,是否有任何简洁的语法来合并两个地图:
Map<String, Map<String, Set<Long>>> m1
Map<String, Map<String, Set<Long>>> m2
并且不要更改m1,m2中的任何元素,甚至更改mergedMap。
例如:
m1包含2个元素,如:
{
"k1": {
"v1": [
11,
12
]
},
"k2": {
"v2": [
21
]
}
}
m2包含3个元素,如:
{
"k1": {
"v11": [
11
]
},
"k2": {
"v2": [
21,
22
]
},
"k3": {
"v3": [
31
]
}
}
我想要的合并地图是合并的3个元素。
特别是,&#34; k1&#34;的值由m1和m2组合而成。
{
"k1": {
"v1": [
11,
12
],
"v11": [
11
]
},
"k2": {
"v2": [
21,
22
]
},
"k3": {
"v3": [
31
]
}
}
当我在合并的Map中添加一些元素时,键是&lt;&#34; k3&#34;,&lt;&#34; v3&#34;,???&gt;&gt;。
我不希望原始地图m2的元素再次修改。
答案 0 :(得分:4)
在不修改源集合的情况下合并嵌套集合比第一眼看上去更复杂。在原地执行合并,修改其中一个源映射时,Map.merge
的嵌套应用程序将执行,但是为了将嵌套数据收集到新容器中,类似于Java 9的构造{{3}是必要的。使用此收集器,解决方案可能如下所示:
Map<String, Map<String, Set<Long>>> m3 =
Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey,
flatMapping(e -> e.getValue().entrySet().stream(),
groupingBy(Map.Entry::getKey, flatMapping(e -> e.getValue().stream(), toSet())))));
当使用flatMapping
收集器的后端端口时,这也适用于Java 8(参见flatMapping
collector的末尾)。
另一种方法是创建专门针对此用例的收集器,考虑到要合并的Map
的数量相当小:
static <T> Collector<Set<T>,?,Set<T>> mergeSets() {
return Collector.of(HashSet::new, Set::addAll, (s1,s2)->{ s1.addAll(s2); return s1; });
}
static <K,V> Collector<Map<K,V>,?,Map<K,V>> mergeMaps(Collector<V,?,V> c) {
return collectingAndThen(reducing(
(m1,m2) -> Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, c)))),
o -> o.orElse(Collections.emptyMap()));
}
这些收藏家可以合并完成这项工作:
Map<String, Map<String, Set<Long>>> m3 =
Stream.of(m1, m2).collect(mergeMaps(mergeMaps(mergeSets())));
答案 1 :(得分:2)
种类:
HashMap<String, Map<String, Set<String>>> m1 = new HashMap<>();
HashMap<String, Map<String, Set<String>>> m2 = new HashMap<>();
Stream.of(m1,m2).flatMap( m -> m.entrySet().stream())
// stream of entries <String,Set<String>
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue(), (s1, s2) -> { /* do whatever you like to merge your nested maps */ return new HashMap<>()} )
`
当然,您必须合并嵌套的地图。 这将保留原始数据结构
答案 2 :(得分:1)
Streams并不是所有内容的替代品,所以这是我的观点:
for (Map.Entry<String, Map<String, Set<Long>>> entry : m2.entrySet()) {
m1.merge(entry.getKey(), entry.getValue(), (v1, v2) -> {
for (Map.Entry<String, Set<Long>> e : v2.entrySet()) {
v1.merge(e.getKey(), e.getValue(), (s1, s2) -> {
s1.addAll(s2);
return s1;
});
}
return v1;
});
}
或者使用 flatMap ,如其他建议的答案:
Stream.of(m1, m2)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue, (v1, v2) -> {
for (Map.Entry<String, Set<Long>> e : v2.entrySet()) {
v1.merge(e.getKey(), e.getValue(), (s1, s2) -> {
s1.addAll(s2);
return s1;
});
}
return v1;
}, HashMap::new));
输入您的信息:
[k1={v1=[11, 12]}, k2={v2=[21]}]
{k1={v11=[11]}, k2={v2=[21, 22]}, k3={v3=[31]}}
输出将是:
{k1={v11=[11], v1=[11, 12]}, k2={v2=[21, 22]}, k3={v3=[31]}}