Merge Map <string,list <string =“”> Java 8 Stream

时间:2016-03-24 22:59:23

标签: java collections lambda java-8 java-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>>();

我尝试使用此实现:

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的新密钥。如果密钥在mapGlobalmapAdded中重复,则两个值列表将合并为:A = {1, 3, 5, 7}B = {1, 2, 4, 6},然后A ∪ B = {1, 2, 3, 4, 5, 6, 7}

4 个答案:

答案 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))