如何使用Java Lambda收集List <foo>到Map <bar,list <baz =“” >>?

时间:2018-12-11 21:50:20

标签: java lambda java-stream collectors

我有一个对象Foo,它引用了BarBaz对象:

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转换吗?

3 个答案:

答案 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::getBarkeyMapper函数,用于提取地图密钥。
  • 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())));