我想将两个Map与JAVA 8 Stream合并:
Map<String, List<String>> mapGlobal = new HashMap<String, List<String>>();
Map<String, List<String>> mapAdded = new HashMap<String, List<String>>();
我尝试使用此实现:
mapGlobal = Stream.of(mapGlobal, mapAdded)
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())
));
但是,此实现仅创建如下结果:
Map<String, List<Object>>
如果mapGlobal
中没有包含一个密钥,它将被添加为具有相应List of String的新密钥。如果密钥在mapGlobal
和mapAdded
中重复,则两个值列表将合并为:A = {1, 3, 5, 7}
和B = {1, 2, 4, 6}
,然后A ∪ B = {1, 2, 3, 4, 5, 6, 7}
。
答案 0 :(得分:11)
您可以通过迭代mapAdded
中的所有条目并将它们合并到mapGlobal
来完成此操作。
以下内容通过调用forEach(action)
来迭代mapAdded
的条目,其中操作会消耗每个条目的键和值。对于每个条目,我们在mapGlobal
上致电merge(key, value, remappingFunction)
:如果密钥不存在,则会在密钥k
下创建条目,并创建值v
如果它们已经存在,将调用给定的重映射函数。此函数将合并2个列表,在这种情况下,首先将其添加到TreeSet
以确保唯一和已排序的元素并转换回列表:
mapAdded.forEach((k, v) -> mapGlobal.merge(k, v, (v1, v2) -> {
Set<String> set = new TreeSet<>(v1);
set.addAll(v2);
return new ArrayList<>(set);
}));
如果您想并行运行,可以通过获取entrySet()
并在其上调用parallelStream()
来创建Stream管道。但是,您需要确保使用支持mapGlobal
并发的映射,如ConcurrentHashMap
。
ConcurrentMap<String, List<String>> mapGlobal = new ConcurrentHashMap<>();
// ...
mapAdded.entrySet().parallelStream().forEach(e -> mapGlobal.merge(e.getKey(), e.getValue(), (v1, v2) -> {
Set<String> set = new TreeSet<>(v1);
set.addAll(v2);
return new ArrayList<>(set);
}));
答案 1 :(得分:3)
在Map上使用foreach可用于合并给定的arraylist。
public Map<String, ArrayList<String>> merge(Map<String, ArrayList<String>> map1, Map<String, ArrayList<String>> map2) {
Map<String, ArrayList<String>> map = new HashMap<>();
map.putAll(map1);
map2.forEach((key , value) -> {
//Get the value for key in map.
ArrayList<String> list = map.get(key);
if (list == null) {
map.put(key,value);
}
else {
//Merge two list together
ArrayList<String> mergedValue = new ArrayList<>(value);
mergedValue.addAll(list);
map.put(key , mergedValue);
}
});
return map;
}
答案 2 :(得分:1)
原始实现不会创建Map<String, List<Object>>
之类的结果,而是Map<String, List<List<String>>>
。您需要额外的Stream管道才能生成Map<String, List<String>>
。
答案 3 :(得分:0)
使用StreamEx
Map<String, List<String>> mergedMap =
EntryStream.of(mapGlobal)
.append(EntryStream.of(mapAdded))
.toMap((v1, v2) -> {
List<String> combined = new ArrayList<>();
combined.addAll(v1);
combined.addAll(v2);
return combined;
});
如果您有更多要合并的地图,只需追加到流中
.append(EntryStream.of(mapAdded2))
.append(EntryStream.of(mapAdded3))