[英]Merge Map<String, List<String> Java 8 Stream
I would like to merge two Map with JAVA 8 Stream:我想合并两个 Map 和 JAVA 8 Stream:
Map<String, List<String>> mapGlobal = new HashMap<String, List<String>>();
Map<String, List<String>> mapAdded = new HashMap<String, List<String>>();
I try to use this implementation:我尝试使用这个实现:
mapGlobal = Stream.of(mapGlobal, mapAdded)
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())
));
However, this implementation only create a result like:但是,此实现只会产生如下结果:
Map<String, List<Object>>
If one key is not contained in the mapGlobal
, it would be added as a new key with the corresponding List of String.如果一个键不包含在
mapGlobal
中,它将作为一个新键添加到相应的字符串列表中。 If the key is duplicated in mapGlobal
and mapAdded
, both list of values will be merge as: A = {1, 3, 5, 7}
and B = {1, 2, 4, 6}
then A ∪ B = {1, 2, 3, 4, 5, 6, 7}
.如果键在
mapGlobal
和mapAdded
中重复,则两个值列表将合并为: A = {1, 3, 5, 7}
和B = {1, 2, 4, 6}
然后A ∪ B = {1, 2, 3, 4, 5, 6, 7}
。
You can do this by iterating over all the entries in mapAdded
and merging them into mapGlobal
.您可以通过迭代
mapAdded
所有条目并将它们合并到mapGlobal
来做到这mapGlobal
。
The following iterates over the entries of mapAdded
by calling forEach(action)
where the action consumes the key and value of each entry.下面通过调用
forEach(action)
迭代mapAdded
的条目,其中操作消耗每个条目的键和值。 For each entry, we call merge(key, value, remappingFunction)
on mapGlobal
: this will either create the entry under the key k
and value v
if the key didn't exist or it will invoke the given remapping function if they already existed.对于每个条目,我们在
mapGlobal
上调用merge(key, value, remappingFunction)
mapGlobal
:如果键不存在,这将在键k
和值v
下创建条目,或者如果它们已经存在,它将调用给定的重新映射函数。 This function takes the 2 lists to merge, which in this case, are first added to a TreeSet
to ensure both unique and sorted elements and converted back into a list:此函数将 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);
}));
If you want to run that potentially in parallel, you can create a Stream pipeline by getting the entrySet()
and calling parallelStream()
on it.如果您想潜在地并行运行它,您可以通过获取
entrySet()
并在其上调用parallelStream()
来创建一个 Stream 管道。 But then, you need to make sure to use a map that supports concurrency for mapGlobal
, like a ConcurrentHashMap
.但是,您需要确保对
mapGlobal
使用支持并发的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);
}));
Using foreach over Map can be used to merge given arraylist.在 Map 上使用 foreach 可用于合并给定的数组列表。
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;
}
The original implementation doesn't create result like Map<String, List<Object>>
, but Map<String, List<List<String>>>
.原始实现不会创建像
Map<String, List<Object>>
,而是Map<String, List<List<String>>>
。 You need additional Stream pipeline on it to produce Map<String, List<String>>
.您需要额外的 Stream 管道来生成
Map<String, List<String>>
。
Map<String, List<String>> result = new HashMap<String, List<String>>();
Map<String, List<String>> map1 = new HashMap<String, List<String>>();
Map<String, List<String>> map2 = new HashMap<String, List<String>>();
for(Map.Entry<String, List<String>> entry: map1.entrySet()) {
result.put(entry.getKey(), new ArrayList<>(entry.getValue());
}
for(Map.Entry<String, List<String>> entry: map2.entrySet()) {
if(result.contains(entry.getKey())){
result.get(entry.getKey()).addAll(entry.getValue());
} else {
result.put(entry.getKey(), new ArrayList<>(entry.getValue());
}
}
This solution creates independent result map without any reference to map1 and map2 lists.此解决方案创建独立的结果 map,而不引用 map1 和 map2 列表。
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;
});
If you have even more maps to merge just append to the stream如果您有更多地图要合并,只需附加到流
.append(EntryStream.of(mapAdded2))
.append(EntryStream.of(mapAdded3))
Here is the full code to Iterate Two HashMap which have values stored in the form of list. Merging all the key and values in first hashmap. Below is the example.
HashMap<String, List<String>> hmap1 = new HashMap<>();
List<String> list1 = new LinkedList<>();
list1.add("000");
list1.add("111");
List<String> list2 = new LinkedList<>();
list2.add("222");
list2.add("333");
hmap1.put("Competitor", list1);
hmap1.put("Contractor", list2);
// System.out.println(hmap1);
HashMap<String, List<String>> hmap2 = new HashMap<>();
List<String> list3 = new LinkedList<>();
list3.add("aaa");
list3.add("bbb");
List<String> list4 = new LinkedList<>();
list4.add("ccc");
list4.add("ddd");
hmap2.put("Competitor", list3);
hmap2.put("Contractor", list4);
//******* Java 8 Feature *****
hmap1.forEach((k, v) -> hmap2.merge(k, v, (v1, v2) -> {
List<String> li = new LinkedList<>(v1);
li.addAll(v2);
hmap2.put(k,li);
return new ArrayList<>(li);
}));
System.out.println(hmap2);
Output - {Competitor=[aaa, bbb, 000, 111], Contractor=[ccc, ddd, 222, 333]}输出 - {竞争者=[aaa, bbb, 000, 111], 承包商=[ccc, ddd, 222, 333]}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.