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

我有一个类型列表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选项,但无法获得所需的结果。


MMMHUHU
浏览 187回答 4
4回答

慕森王

您可以将toMap收集器与有界方法引用一起使用来获取您需要的内容。另请注意,此解决方案假设您的源容器中没有重复的 A 实例。如果该前提条件成立,则该解决方案将为您提供所需的结果。它看起来是这样的。Map<A,&nbsp;Collection<B>>&nbsp;resultMap&nbsp;=&nbsp;listofA.stream() &nbsp;&nbsp;&nbsp;&nbsp;.collect(Collectors.toMap(Function.identity(),&nbsp;repo::getListofB);如果您有重复的 A 元素,那么除了上面给出的功能之外,您还必须使用此合并功能。合并功能可以处理键冲突(如果有)。Map<A,&nbsp;Collection<B>>&nbsp;resultMap&nbsp;=&nbsp;listofA.stream() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.collect(Collectors.toMap(Function.identity(),&nbsp;repo::getListofB,&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(a,&nbsp;b)&nbsp;->&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.addAll(b); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;a; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}));这里有一个更简洁的 Java9 方法,它使用flatMapping收集器来处理重复的 A 元素。Map<A,&nbsp;List<B>>&nbsp;aToBmap&nbsp;=&nbsp;listofA.stream() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.collect(Collectors.groupingBy(Function.identity(), &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collectors.flatMapping(a&nbsp;->&nbsp;getListofB(a).stream(),&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collectors.toList())));

月关宝盒

这将是直截了当的,listofA.stream().collect(toMap(Function.identity(),&nbsp;a&nbsp;->&nbsp;getListofB(a)));

料青山看我应如是

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

米琪卡哇伊

要收集一个Map其中键是A未更改的对象,值是对应B对象的列表,可以将toList()收集器替换为以下收集器:toMap(Function.identity(),&nbsp;a&nbsp;->&nbsp;repo.getListOfB(a))第一个参数定义如何从原始对象计算密钥identity():保持流的原始对象不变。第二个参数定义了如何计算该值,因此这里它仅包含对将 a 转换A为 的列表的方法的调用B。由于该repo方法仅采用一个参数,因此您还可以通过用方法引用替换 lambda 来提高清晰度:toMap(Function.identity(),&nbsp;repo::getListOfB)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java