我有List<SomeBean>
。 SomeBean
包含一个返回K
的方法,该方法可能在列表中重复,另一个方法返回List<V>
。由于我使用SomeBean
的方式,它几乎类似于具有键K
值List<V>
的条目。
我想将其转换为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())));
}
然而,这目前分两步完成。如何在不使用中间一次性Map<K, List<List<V>>>
的情况下执行相同的操作?
答案 0 :(得分: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; }));
}
注意:我在值映射器函数中创建了一个新的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]));
}
你可以这样使用它:
return paginationResult.stream()
.collect(Collectors.groupingBy(
SomeBean::getK,
flatMapping(
someBean -> someBean.getV().stream(),
Collectors.toList())));
注2:我从this answer given by user @Holger开始实施flatMapping
方法。
答案 1 :(得分:1)
使用其他下游收集器collectingAndThen
。
private static Map<K, List<V>> transformToMapOfList(List<SomeBean> paginationResult) {
return paginationResult.stream()
.collect(Collectors.groupingBy(
SomeBean::getK,
Collectors.mapping(
SomeBean::getV,
Collectors.collectingAndThen(
Collectors.toList(),
lists -> lists.stream().flatMap(Collection::stream).collect(Collectors.toList())
)
)
));
}
collectingAndThen
与Collectors.toList()
相结合,可以在结果集合上应用函数,允许将其映射到任何类型。
由于没有在网上找到任何答案,我试图解决这个问题,在试图做一些疯狂的低效率还原操作时,我的头脑几个小时,这让我的IDE和编译器严重消化不良。