为了账号安全,请及时绑定邮箱和手机立即绑定

使用 Collectors.toMap 或 groupingBy 在 Map 中收集映射操作的结果

使用 Collectors.toMap 或 groupingBy 在 Map 中收集映射操作的结果

MMMHUHU 2023-09-20 15:18:26
我有一个类型列表List<A>,并通过映射操作获取合并在一个列表中的所有 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选项,但无法获得所需的结果。
查看完整描述

4 回答

?
慕森王

TA贡献1777条经验 获得超3个赞

您可以将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())));


查看完整回答
反对 回复 2023-09-20
?
月关宝盒

TA贡献1772条经验 获得超5个赞

这将是直截了当的,

listofA.stream().collect(toMap(Function.identity(), a -> getListofB(a)));


查看完整回答
反对 回复 2023-09-20
?
料青山看我应如是

TA贡献1772条经验 获得超7个赞

在这个答案中,我将展示如果列表中有重复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)。

文档中明确指出了这一点:

如果映射的键包含重复项(根据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)。


查看完整回答
反对 回复 2023-09-20
?
米琪卡哇伊

TA贡献1998条经验 获得超6个赞

要收集一个Map其中键是A未更改的对象,值是对应B对象的列表,可以将toList()收集器替换为以下收集器:

toMap(Function.identity(), a -> repo.getListOfB(a))

一个参数定义如何从原始对象计算密钥identity():保持流的原始对象不变。

第二参数定义了如何计算该,因此这里它仅包含对将 a 转换A为 的列表的方法的调用B

由于该repo方法仅采用一个参数,因此您还可以通过用方法引用替换 lambda 来提高清晰度:

toMap(Function.identity(), repo::getListOfB)


查看完整回答
反对 回复 2023-09-20
  • 4 回答
  • 0 关注
  • 85 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信