如何使用 Java lambda 将 List<Foo> 收集到 Map<Bar, List<Baz>>?
How to collect a List<Foo> to a Map<Bar, List<Baz>> using Java lambdas?
我有一个对象 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 转换?
我想你想要
list.stream().collect(groupingBy(Foo::getBar,
mapping(Foo::getBaz, toList())));
其中 getBaz
是 "downstream collector",它转换分组的 Foo
s,然后另一个创建列表。
要将经典 grouping
更改为 Map<Bar, List<Foo>>
,您需要使用允许更改地图值的方法:
- 有下游的版本Collectors.groupingBy(classifier, downstream)
- 这是一个映射操作Collectors.mapping(mapper, downstream)
- 这需要另一个操作来设置容器Collectors.toList()
//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())));
你很接近,你需要提供一个 "downstream" 收集器来进一步完善你的标准。在这种情况下,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
值的两个列表。
我有一个对象 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 转换?
我想你想要
list.stream().collect(groupingBy(Foo::getBar,
mapping(Foo::getBaz, toList())));
其中 getBaz
是 "downstream collector",它转换分组的 Foo
s,然后另一个创建列表。
要将经典 grouping
更改为 Map<Bar, List<Foo>>
,您需要使用允许更改地图值的方法:
- 有下游的版本Collectors.groupingBy(classifier, downstream)
- 这是一个映射操作Collectors.mapping(mapper, downstream)
- 这需要另一个操作来设置容器Collectors.toList()
//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())));
你很接近,你需要提供一个 "downstream" 收集器来进一步完善你的标准。在这种情况下,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
值的两个列表。