合并映射<字符串, 列表<字符串> Java 8 流

2022-09-02 09:52:26

我想将两个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>>

如果 一个键不包含在 中,它将作为新键与相应的字符串列表一起添加。如果 键在 和 中重复,则两个值列表将合并为:,然后合并为 。mapGlobalmapGlobalmapAddedA = {1, 3, 5, 7}B = {1, 2, 4, 6}A ∪ B = {1, 2, 3, 4, 5, 6, 7}


答案 1

您可以通过循环访问 中的所有条目并将其合并到 .mapAddedmapGlobal

下面通过调用 forEach(action) 循环访问 的条目,其中操作使用每个条目的键和值。对于每个条目,我们在 上调用 merge(key, value, remappingFunction): 如果键不存在,这将在键和值下创建条目,或者如果键已经存在,它将调用给定的重新映射函数。此函数将 2 个列表合并,在本例中,首先将它们添加到 a 中,以确保元素唯一和排序,并转换回列表:mapAddedmapGlobalkvTreeSet

mapAdded.forEach((k, v) -> mapGlobal.merge(k, v, (v1, v2) -> {
    Set<String> set = new TreeSet<>(v1);
    set.addAll(v2);
    return new ArrayList<>(set);
}));

如果要并行运行该管道,可以通过获取并调用 Stream 管道来创建该管道。但是,您需要确保使用支持 并发的映射,例如 .entrySet()parallelStream()mapGlobalConcurrentHashMap

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);
}));

答案 2

在 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;
}