我有一个类型为List<A>
的列表,并且通过map操作为所有合并在一个列表中的所有A元素获得了一个类型为List<B>
的集合列表。
List<A> listofA = [A1, A2, A3, A4, A5, ...]
List<B> listofB = listofA.stream()
.map(a -> repo.getListofB(a))
.flatMap(Collection::stream)
.collect(Collectors.toList());
没有平面图
List<List<B>> listOflistofB = listofA.stream()
.map(a -> repo.getListofB(a))
.collect(Collectors.toList());
我想将结果收集为Map<A, List<B>>
类型的映射,并且到目前为止尝试使用各种Collectors.toMap
或Collectors.groupingBy
选项,但无法获得所需的结果。
答案 0 :(得分:8)
您可以将toMap
收集器与有限方法引用一起使用以获取所需的内容。还要注意,该解决方案假定您在源容器中没有重复的A实例。如果该前提成立,则该解决方案将为您提供所需的结果。看起来就是这样。
Map<A, Collection<B>> resultMap = listofA.stream()
.collect(Collectors.toMap(Function.identity(), repo::getListofB);
如果有重复的A元素,则除了上面给出的内容外,还必须使用此合并功能。合并功能处理键冲突(如果有)。
Map<A, Collection<B>> resultMap = listofA.stream()
.collect(Collectors.toMap(Function.identity(), repo::getListofB,
(a, b) -> {
a.addAll(b);
return a;
}));
这是一种更简洁的Java9方法,它使用flatMapping
收集器来处理重复的A元素。
Map<A, List<B>> aToBmap = listofA.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.flatMapping(a -> getListofB(a).stream(),
Collectors.toList())));
答案 1 :(得分:3)
这很简单
listofA.stream().collect(toMap(Function.identity(), a -> getListofB(a)));
答案 2 :(得分:2)
要收集Map
,其中键是不变的A
对象,而值是相应的B
对象的列表,可以将toList()
收集器替换为以下收集者:
toMap(Function.identity(), a -> repo.getListOfB(a))
first 参数定义了如何从原始对象计算 key :identity()
使流的原始对象保持不变。
second 参数定义了值的计算方式,因此此处仅包含对您的方法的调用,该方法将A
转换为以下内容的列表: B
。
由于repo
方法仅使用一个参数,因此您还可以通过将lambda替换为方法引用来提高清晰度:
toMap(Function.identity(), repo::getListOfB)
答案 3 :(得分:2)
在这个答案中,我显示的是如果您在A
列表中重复了List<A> listofA
个元素,将会发生什么情况。
实际上,如果listofA
中存在重复项,则以下代码将引发IllegalStateException
:
Map<A, Collection<B>> resultMap = listofA.stream()
.collect(Collectors.toMap(
Function.identity(),
repo::getListofB);
可能会引发异常,因为当键冲突时(例如,当键映射器函数返回重复项时,Collectors.toMap
不知道如何合并)如果Function.identity()
列表中有重复的元素,则listofA
就是这种情况。
这是明确说明的in the docs:
如果映射的键包含重复项(根据
Object.equals(Object)
),则在执行收集操作时将引发IllegalStateException
。如果映射的键可能有重复,请改用toMap(Function, Function, BinaryOperator
)。
文档还为我们提供了解决方案:如果存在重复的元素,我们需要提供一种合并值的方法。这是一种这样的方式:
Map<A, Collection<B>> resultMap = listofA.stream()
.collect(Collectors.toMap(
Function.identity(),
a -> new ArrayList<>(repo.getListofB(a)),
(left, right) -> {
left.addAll(right);
return left;
});
这使用Collectors.toMap
的重载版本,该版本接受合并函数作为其第三个参数。在合并功能中,Collection.addAll
用于将每个重复的B
元素的A
个元素添加到每个A
的非队列列表中。
在值映射器函数中,创建了一个新的ArrayList
,因此每个List<B>
的原始A
不会发生突变。另外,在创建Arraylist
时,我们事先知道可以对其进行突变(即,以后可以在其中添加元素,以防listofA
中有重复项)。