使用 Java 8 Lambda 表达式合并映射流

2022-09-03 09:15:31

我有两个映射和类型,它们必须合并成一个映射,其中两个映射中相同键的值被收集到一个列表中并放入一个新的Map中。m1m2Map<Integer, String>Map<Integer, List<String>>

基于我探索的解决方案:

Map<Integer, List<String>> collated =
        Stream.concat(m1.entrySet().stream(), m2.entrySet().stream()).collect(
                Collectors.toMap(Entry::getKey,
                        Entry::getValue, (a, b) -> {
                            List<String> merged = new ArrayList<String>(a);
                            merged.addAll(b);
                            return merged;
                        }));

但是,此解决方案期望源,因为 toMap 中的合并函数期望操作数和结果属于同一类型。ListMap<Integer, List<String>>

我不想更改源集合。请提供您关于使用 lambda 表达式实现此目的的意见。


答案 1

这是按收集器分组的工作:

Stream.of(m1,m2)
        .flatMap(m->m.entrySet().stream())
        .collect(groupingBy(
                Map.Entry::getKey,
                mapping(Map.Entry::getValue, toList())
        ));

答案 2

我现在无法测试它,但我认为您只需要它来更改值的映射,从到包含该值的列表:Entry::getValue

Map<Integer, List<String>> collated =
        Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
                .collect(Collectors.toMap(Entry::getKey,
                        e -> {
                            List<String> v = new ArrayList<String>();
                            v.add(e.getValue());
                            return v;
                        },
                        (a, b) -> {
                            List<String> merged = new ArrayList<String>(a);
                            merged.addAll(b);
                            return merged;
                        }));

编辑:这个想法是正确的。语法不是。当前的语法有效,尽管有点难看。必须有一种更短的方法来编写它。

也可以替换为 。e -> {..}e -> new ArrayList<String>(Arrays.asList(new String[]{e.getValue()}))

或与e -> Stream.of(e.getValue()).collect(Collectors.toList())

或者你可以用:groupingBy

Map<Integer, List<String>> collated =
        Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
                .collect(Collectors.groupingBy(Map.Entry::getKey,
                        Collectors.mapping(Map.Entry::getValue,
                                Collectors.toList())));