繁体   English   中英

使用 Java 8 Lambda 表达式合并 Map 流

[英]Merging Map streams using Java 8 Lambda Expression

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

基于我探索的解决方案:

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

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

我不想更改源集合。 请提供有关使用 lambda 表达式实现此目标的输入。

这是groupingBy收集器的工作:

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

我现在不能测试它,但我认为你需要它来将值的映射从Entry::getValue更改为包含该值的 List :

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

如果您想要纯 Java-8 解决方案,Misha 的解决方案是最好的。 如果您不介意使用第三方库,那么使用我的StreamEx会短一些

Map<Integer, List<String>> map = StreamEx.of(m1, m2)
        .flatMapToEntry(Function.identity())
        .grouping();

在内部,它与 Misha 的解决方案相同,只是语法糖。

这似乎是使用 Guava 的Multimap的绝佳机会。

ListMultimap<Integer, String> collated = ArrayListMultimap.create();
collated.putAll(Multimaps.forMap(m1));
collated.putAll(Multimaps.forMap(m2));

如果你真的需要一个Map<Integer, List<String>>

Map<Integer, List<String>> mapCollated = Multimaps.asMap(collated);

为清楚起见,您可以使用带有三个参数的Collectors.toMap方法。

Map<Integer, String> m1 = Map.of(1, "A", 2, "B");
Map<Integer, String> m2 = Map.of(1, "C", 2, "D");
// two maps into one
Map<Integer, List<String>> m3 = Stream
        .of(m1.entrySet(), m2.entrySet())
        .flatMap(Collection::stream)
        .collect(Collectors.toMap(
                // key - Integer
                e -> e.getKey(),
                // value - List<String>
                e -> List.of(e.getValue()),
                // mergeFunction - two lists into one
                (list1, list2) -> {
                    List<String> list = new ArrayList<>();
                    list.addAll(list1);
                    list.addAll(list2);
                    return list;
                }));
// output
System.out.println(m3); // {1=[A, C], 2=[B, D]}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM