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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31488339/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 18:41:28  来源:igfitidea点击:

Merging Map streams using Java 8 Lambda Expression

javalambdajava-8java-stream

提问by viktor

I am new to lambda expression and was trying to use it in my assignment.

我是 lambda 表达式的新手,并试图在我的作业中使用它。

The problem:

问题:

I have two maps m1and m2of type Map<Integer, String>, which has to be merged into a single map Map<Integer, List<String>>, where values of same keys in both the maps are collected into a List and put into a new Map.

我有两个 mapm1m2type Map<Integer, String>,它们必须合并到一个 map 中 Map<Integer, List<String>>,其中两个 map 中相同键的值被收集到一个 List 中并放入一个新的 Map 中。

Solution based on what I explored:

基于我探索的解决方案:

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

But, this solution expects source Listto be Map<Integer, List<String>>as the merge function in toMap expects operands and result to be of the same type.

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

I don't want to change the source collection. Please provide your inputs on achieving this using lambda expression.

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

采纳答案by Eran

I can't test it right now, but I think all you need it to change the mapping of the value from Entry::getValue to a List that contains that value :

我现在不能测试它,但我认为你需要它来将值的映射从 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;
                                    }));

EDIT: The idea was correct. The syntax wasn't. Current syntax works, though a bit ugly. There must be a shorter way to write it.

编辑:这个想法是正确的。语法不是。当前的语法有效,虽然有点难看。必须有更短的写法。

You can also replace e -> {..}with e -> new ArrayList<String>(Arrays.asList(new String[]{e.getValue()})).

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

or with e -> Stream.of(e.getValue()).collect(Collectors.toList())

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

EDIT :

编辑 :

Or you can do it with groupingBy:

或者你可以这样做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())));

回答by Misha

That's a job for groupingBycollector:

这是groupingBy收藏家的工作:

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

回答by Tagir Valeev

Misha's solution is the best if you want pure Java-8 solution. If you don't mind using third-party libraries, it would be a little shorter using my StreamEx.

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

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

Internally it's the same as in Misha's solution, just syntactic sugar.

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

回答by Jeffrey

This seems like a great opportunity to use Guava's Multimap.

这似乎是使用 Guava 的Multimap.

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

And if you really need a Map<Integer, List<String>>:

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

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