Java Streams:获取按内部映射键分组的值

hot*_*key 14 java grouping java-8 java-stream collectors

我有Map<A, Map<B, C>>,我想Map<B, List<C>>使用Java Streams 从中获取.

我尝试按如下方式进行:

public <A, B, C> Map<B, List<C>> groupsByInnerKey(Map<A, Map<B, C>> input) {
    return input.values()
            .stream()
            .flatMap(it -> it.entrySet().stream())
            .collect(Collectors.groupingBy(Map.Entry::getKey));
}
Run Code Online (Sandbox Code Playgroud)

我期待的是:

  • flatMap给人Stream的Map.Entry<B, C>
  • collect(Collectors.groupingBy(...))获取应用于Map.Entry<B, C>和返回的函数B,从而收集C到的值List<C>.

但它没有编译,字面意思:

无法从静态上下文引用非静态方法

在Map.Entry::getKey最后一行.

有人可以解释什么是错的或什么是实现我想要的正确方法?

Tun*_*aki 13

您的Stream由Map.Entry对象组成,但是您希望收集的实际上是条目的值,而不是条目本身.使用您当前的代码,您将获得一个Map<B, List<Map.Entry<B, C>>>.

因此,你只是错过了一个电话Collectors.mapping.此收集器将使用给定的映射器函数映射Stream元素,并将该结果收集到下游容器中.在这种情况下,映射器是Map.Entry::getValue(所以从映射条目返回值),下游收集器收集到List.

public <A, B, C> Map<B, List<C>> groupsByInnerKey(Map<A, Map<B, C>> input) {
    return input.values()
            .stream()
            .flatMap(it -> it.entrySet().stream())
            .collect(Collectors.groupingBy(
                 Map.Entry::getKey,
                 Collectors.mapping(Map.Entry::getValue, Collectors.toList())
            ));
}
Run Code Online (Sandbox Code Playgroud)


Era*_*ran 8

您的流管道返回a Map<B, List<Map.Entry<B,C>>>,而不是a Map<B, List<C>>.

要得到什么Map<B, List<C>>,你需要添加一个mapping映射Map.Entry<B,C>到C:

return input.entrySet()
        .stream()
        .flatMap(it -> it.getValue().entrySet().stream())
        .collect(Collectors.groupingBy(Map.Entry::getKey,Collectors.mapping(Map.Entry::getValue,Collectors.toList())));
Run Code Online (Sandbox Code Playgroud)