我想使用Java Stream来运行POJO列表,例如下面的列表List<A>
,并将其转换为Map Map<String, Set<String>>
。
例如,A类是:
class A {
public String name;
public String property;
}
我编写了下面的代码,将值收集到地图Map<String, String>
:
final List<A> as = new ArrayList<>();
// the list as is populated ...
// works if there are no duplicates for name
final Map<String, String> m = as.stream().collect(Collectors.toMap(x -> x.name, x -> x.property));
但是,因为可能有多个POJO具有相同的name
,所以我希望地图的值为Set
。同一个密钥property
的所有name
字符串都应该放在同一个字符集中。
如何做到这一点?
// how do i create a stream such that all properties of the same name get into a set under the key name
final Map<String, Set<String>> m = ???
答案 0 :(得分:19)
groupingBy完全符合您的要求:
import static java.util.stream.Collectors.*;
...
as.stream().collect(groupingBy((x) -> x.name, mapping((x) -> x.property, toSet())));
答案 1 :(得分:2)
@Nevay的回答绝对是使用groupingBy
的正确方法,但toMap
也可以通过添加mergeFunction作为第三个参数来实现:
as.stream().collect(Collectors.toMap(x -> x.name,
x -> new HashSet<>(Arrays.asList(x.property)),
(x,y)->{x.addAll(y);return x;} ));
此代码将数组映射到地图,其中密钥为x.name
,值为HashSet
,其中一个值为x.property
。当存在重复的键/值时,然后调用第三个参数merger函数来合并两个HashSet。
PS。如果您使用Apache Common库,您也可以使用他们的SetUtils::union
作为合并
答案 2 :(得分:0)
此外,您可以使用Collectors.toMap函数的合并功能选项 Collectors.toMap(keyMapper,valueMapper,mergeFunction)如下:
final Map<String, String> m = as.stream()
.collect(Collectors.toMap(
x -> x.name,
x -> x.property,
(property1, property2) -> property1+";"+property2);
答案 3 :(得分:0)
相同但不同
Map<String, Set<String>> m = new HashMap<>();
as.forEach(a -> {
m.computeIfAbsent(a.name, v -> new HashSet<>())
.add(a.property);
});