我有一个对象Foo
,它引用了Bar
和Baz
对象:
public class Foo {
private Bar bar;
private Baz baz;
public Foo(Bar bar, Baz baz) {
this.bar = bar;
this.baz = baz;
}
}
我有一个List<Foo>
想要转换为Map
。我希望键为Bar
,而值应为List<Baz>
。
我可以创建一个Map
,其中Bar
是键,值是一个List<Foo>
:
Map<Bar, List<Foo>> mapBarToFoos = foos.stream().collect(Collectors.groupingBy(Foo::getBar));
我不知道如何执行最后一步,并将值List转换为List<Baz>
。对我没有看到的值进行lambda转换吗?
答案 0 :(得分:3)
我想你想要
list.stream().collect(groupingBy(Foo::getBar,
mapping(Foo::getBaz, toList())));
其中getBaz
是“下游收集器”,它转换成组的Foo
,然后再转换一个创建列表。
答案 1 :(得分:3)
您已经很接近了,您需要提供一个“下游”收集器来进一步完善您的条件。在这种情况下,groupingBy
方法和mapping
下游收集器是惯用方法,即
list.stream().collect(groupingBy(Foo::getBar, mapping(Foo::getBaz, toList())));
这实际上是通过将mapping
下游收集器应用于分类(Foo::getBar
)函数的结果来实现的。
基本上,我们要做的是将每个Foo
对象映射到Baz
并将其放入列表中。
只想在此处显示另一个变体,尽管不如groupingBy
方法可读:
foos.stream()
.collect(toMap(Foo::getBar, v -> new ArrayList<>(singletonList(v.getBaz())),
(l, r) -> {l.addAll(r); return l;}));
Foo::getBar
是keyMapper
函数,用于提取地图密钥。v -> new ArrayList<>(singletonList(v))
是valueMapper
函数来提取地图值。(l, r) -> {l.addAll(r); return l;}
是用于合并的合并函数
合并两个碰巧具有相同getBar
值的列表。答案 2 :(得分:2)
要将经典的grouping
更改为Map<Bar, List<Foo>>
,您需要使用允许更改地图值的方法:
//Use the import to reduce the Collectors. redundancy
//import static java.util.stream.Collectors.*;
Map<Bar, List<Baz>> mapBarToFoos =
foos.stream().collect(groupingBy(Foo::getBar, mapping(Foo::getBaz, toList())));
//without you'll get
Map<Bar, List<Baz>> mapBarToFoos =
foos.stream().collect(Collectors.groupingBy(Foo::getBar, Collectors.mapping(Foo::getBaz, Collectors.toList())));