使用 Collectors.toMap 或 groupingBy 在 Map 中收集 map 操作的结果
Collect results of a map operation in a Map using Collectors.toMap or groupingBy
我有一个 List<A>
类型的列表,并且通过 map 操作获得了一个 List<B>
类型的集合列表,用于合并到一个列表中的所有 A 元素。
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
选项,但无法获得所需的结果。
您可以使用带有有限方法引用的 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())));
收集一个Map
,key是A
object不变,value是对应B
object的列表,您可以用以下收集器替换 toList()
收集器:
toMap(Function.identity(), a -> repo.getListOfB(a))
first 参数定义了如何从原始 object 计算 key :identity()
采用流的原始object不变。
second 参数定义了 value 的计算方式,因此这里它仅包含对转换 value 的方法的调用=13=] 到 B
.
的列表
由于 repo
方法只接受一个参数,您还可以通过将 lambda 替换为方法引用来提高清晰度:
toMap(Function.identity(), repo::getListOfB)
这将是直截了当的,
listofA.stream().collect(toMap(Function.identity(), a -> getListofB(a)));
在这个答案中,我展示了如果您在 List<A> listofA
列表中重复 A
个元素会发生什么。
实际上,如果 listofA
中有重复项,以下代码将抛出 IllegalStateException
:
Map<A, Collection<B>> resultMap = listofA.stream()
.collect(Collectors.toMap(
Function.identity(),
repo::getListofB);
可能会抛出异常,因为 Collectors.toMap
不知道如何在键发生冲突时 合并 值(即当键映射器函数 returns 重复,如果 listofA
列表中有重复的元素,Function.identity()
就是这种情况。
这个说的很清楚in the docs:
If the mapped keys contains duplicates (according to Object.equals(Object)
), an IllegalStateException
is thrown when the collection operation is performed. If the mapped keys may have duplicates, use toMap(Function, Function, BinaryOperator
) instead.
文档也给了我们解决方案:如果有重复的元素,我们需要提供一种合并值的方法。这是一种这样的方式:
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
用于将每个重复的 A
元素的 B
元素添加到每个 A
.
的唯一列表中
在值映射器函数中,创建了一个新的ArrayList
,这样每个A
的原始List<B>
就不会发生变异。此外,当我们创建一个 Arraylist
时,我们事先知道它可以被改变(即我们可以稍后向它添加元素,以防 listofA
中有重复项)。
我有一个 List<A>
类型的列表,并且通过 map 操作获得了一个 List<B>
类型的集合列表,用于合并到一个列表中的所有 A 元素。
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
选项,但无法获得所需的结果。
您可以使用带有有限方法引用的 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())));
收集一个Map
,key是A
object不变,value是对应B
object的列表,您可以用以下收集器替换 toList()
收集器:
toMap(Function.identity(), a -> repo.getListOfB(a))
first 参数定义了如何从原始 object 计算 key :identity()
采用流的原始object不变。
second 参数定义了 value 的计算方式,因此这里它仅包含对转换 value 的方法的调用=13=] 到 B
.
由于 repo
方法只接受一个参数,您还可以通过将 lambda 替换为方法引用来提高清晰度:
toMap(Function.identity(), repo::getListOfB)
这将是直截了当的,
listofA.stream().collect(toMap(Function.identity(), a -> getListofB(a)));
在这个答案中,我展示了如果您在 List<A> listofA
列表中重复 A
个元素会发生什么。
实际上,如果 listofA
中有重复项,以下代码将抛出 IllegalStateException
:
Map<A, Collection<B>> resultMap = listofA.stream()
.collect(Collectors.toMap(
Function.identity(),
repo::getListofB);
可能会抛出异常,因为 Collectors.toMap
不知道如何在键发生冲突时 合并 值(即当键映射器函数 returns 重复,如果 listofA
列表中有重复的元素,Function.identity()
就是这种情况。
这个说的很清楚in the docs:
If the mapped keys contains duplicates (according to
Object.equals(Object)
), anIllegalStateException
is thrown when the collection operation is performed. If the mapped keys may have duplicates, usetoMap(Function, Function, BinaryOperator
) instead.
文档也给了我们解决方案:如果有重复的元素,我们需要提供一种合并值的方法。这是一种这样的方式:
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
用于将每个重复的 A
元素的 B
元素添加到每个 A
.
在值映射器函数中,创建了一个新的ArrayList
,这样每个A
的原始List<B>
就不会发生变异。此外,当我们创建一个 Arraylist
时,我们事先知道它可以被改变(即我们可以稍后向它添加元素,以防 listofA
中有重复项)。