Java流:将类属性列表映射到扁平化的Map

3

我们如何通过使用Java Streams以最优化的方式将List<Foo>转换为Map<propertyA,List<propertyB>>。

注意:propertyA不是唯一的

//pseudo-code
class Foo
    propertyA //not unique
    List<propertyB>

到目前为止,我有以下内容:

fooList.stream()
       .collect(Collectors.groupingBy(Foo::propertyA, 
                    Collectors.mapping(Foo::propertyB, Collectors.toList())))

结果会得到一个尚未展开其值的Map<属性A,List<List<属性B>>>

3个回答

5

您可以使用Java 9+ Collectors.flatMapping

Map<propretyA, List<propretyB>> result = fooList.stream()
       .collect(Collectors.groupingBy(Foo::propertyA, 
                Collectors.flatMapping(foo -> foo.propertyB().stream(), 
                                       Collectors.toList())));

另一种(Java8+)方式是使用Collectors.toMap,例如this answer

而另一种Java8+的方法是不使用流,而是使用Map.computeIfAbsent

Map<propretyA, List<propretyB>> result = new LinkedHashMap<>();
fooList.forEach(foo -> result.computeIfAbsent(foo.propertyA(), k -> new ArrayList<>())
                             .addAll(foo.propertyB()));

3
如果Java 9不可用,可以在此答案的末尾找到flatMapping的后移版本。 - Holger

4
这应该就可以了:
    fooList.stream()
           .collect(Collectors.toMap(Foo::getPropertyA, Foo::getPropertyBList, (l1, l2) -> {
               l1.addAll(l2);
               return l1;
           }));

1
您可以使用带有合并函数的Collectors.toMap,在重复键时决定使用哪个List<propertyB>
Map<propertyA, List<propertyB>> collect = list.stream()
        .collect(Collectors.toMap(Foo::getPropertyA, Foo::getList, (l1, l2) -> ???));

否则,您可能会收到IllegalStateException。来自javadoc
如果映射键包含重复项(根据Object.equals(Object)),则在执行集合操作时抛出IllegalStateException。
实现合并函数的方式由您决定,但通常您只想返回2个列表的并集,如:l1.addAll(l2); return l1;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接