使用Java 8 Lambda Expression合并Map流

vik*_*tor 15 java lambda java-8 java-stream

我是lambda表达的新手,并试图在我的任务中使用它.

问题:

我有两个地图m1m2类型Map<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;
                                }));
Run Code Online (Sandbox Code Playgroud)

但是,这种解决方案预计源ListMap<Integer, List<String>>如在toMap合并函数需要操作数和结果是相同的类型.

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

Mis*_*sha 21

这是groupingBy收藏家的工作:

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

  • @viktor,这里应该没有什么真正的区别.在并行流中或收集到数组`concat`可能会更好地执行,因为它正确地计算流的总大小. (2认同)
  • @viktor除了@TagirValeev所说的,我相信`concat`有一个优点,如果你将它作为并行运行,因为`concat`可以在两个组成流中分开,而`flatMap`在当前实现下最多将使用2个线程.我现在无法查看流库源代码,因此我可能会对此感到误解.对于大多数实际(即顺序)用途,两者是等价的,"flatMap"更简洁,所以这就是我使用的. (2认同)

Era*_*ran 11

我现在无法测试它,但我认为你需要它来改变从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;
                                    }));
Run Code Online (Sandbox Code Playgroud)

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

你也可以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())));
Run Code Online (Sandbox Code Playgroud)

  • @viktor您是否尝试过我的原始答案(未通过编译)或我更新的答案? (2认同)