Java 8 Streams:Make Collectors.groupingBy返回Map <K,List <V >>而不是Map <K,List <List <V >>>

Hay*_*Hay 3 java java-8 java-stream

我有一个List<SomeBean>.SomeBean包含一个返回K可能在列表中重复的方法,以及另一个返回的方法List<V>.因为我怎么使用SomeBean,它几乎类似于一个键的条目KList<V>.

我想将它转换为a Map<K, List<V>>,其中List<V>列表与相同键的串联K.这是我做的:

private static Map<K, List<V>> transformToMapOfListInTwoSteps(List<SomeBean> paginationResult) {
    Map<K, List<List<V>>> mapOfListOfList = paginationResult.stream()
            .collect(Collectors.groupingBy(SomeBean::getK, Collectors.mapping(SomeBean::getV, Collectors.toList())));

    return mapOfListOfList.entrySet().stream()
            .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().flatMap(Collection::stream).collect(Collectors.toList())));
}
Run Code Online (Sandbox Code Playgroud)

然而,这目前分两步完成.如何在不使用中间一次性的情况下执行相同的操作Map<K, List<List<V>>>

Fed*_*ner 5

我认为你过于复杂化了一些事情.我只是使用Collectors.toMap接受合并函数的重载来在键上发现碰撞时组合这些值:

private static <K, V> Map<K, List<V>> transformToMapOfListInOneStep(
        List<SomeBean> paginationResult) {

    return paginationResult.stream()
        .collect(Collectors.toMap(
            SomeBean::getK, 
            someBean -> new ArrayList<>(someBean.getV()), 
            (v1, v2) -> { v1.addAll(v2); return v1; }));
}
Run Code Online (Sandbox Code Playgroud)

注意:我ArrayList在值映射器函数中创建了一个新函数,因为我不想修改属性的原始列表SomeBean.

另一种方法是Collectors.groupingBy与下游收集器一起使用,该收集器对值进行平面映射,但这不是在Java 8中实现的(尽管它将在Java 9中提供,请参阅参考资料Collectors.flatMapping).

在Java 8中,这可以实现为:

public static <T, U, A, R> Collector<T, ?, R> flatMapping(
        Function<? super T, ? extends Stream<? extends U>> mapper,
        Collector<? super U, A, R> downstream) {

    BiConsumer<A, ? super U> acc = downstream.accumulator();
    return Collector.of(downstream.supplier(),
        (a, t) -> {
            try (Stream<? extends U> s = mapper.apply(t)) {
                if (s != null) s.forEachOrdered(u -> acc.accept(a, u));
            }
        },
        downstream.combiner(), downstream.finisher(),
        downstream.characteristics().toArray(new Collector.Characteristics[0]));
}
Run Code Online (Sandbox Code Playgroud)

你可以这样使用它:

return paginationResult.stream()
        .collect(Collectors.groupingBy(
                SomeBean::getK,
                flatMapping(
                    someBean -> someBean.getV().stream(),
                    Collectors.toList())));
Run Code Online (Sandbox Code Playgroud)

注2:我flatMapping用户@Holger给出的答案中采用了该方法的实现.

  • 你确定要修改`v1`吗? (2认同)