Java 8 Lambda(只需一步分组和缩小)

时间:2018-01-26 16:21:03

标签: java lambda java-8 grouping java-stream

说我有一个Pair对象列表,

List<Pair<A,B>> listOfPairs = //some list of pairs ; 

我想将此列表分组为Map<A,Set<B>>

目前,我可以分两步完成。第一步按A分组,并返回a Map<A,Set<Pair<A,B>>如下:

   Map<A,Set<Pair<A,B>> intermediateStep =   listOfPairs.stream().collect(Collectors.groupingBy((Pair::getLeft), Collectors.toSet()));

然后我流式传输上面地图的入口集并将它们收集到所需的最终结果中,主要是将每个Pair对象映射到其B值,并将它们收集到一个集合中:

 Map<A, Set<B>> finalResult= intermediateStep.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().stream().map(Pair::getRight).collect(Collectors.toSet())));

有没有更好的方法来实现预期的结果,也许是一步到位?换句话说,上述中间步骤按A分组,但分组的右侧返回整个Pair对象。我想按A分组,并在一步中将A指向其相关B的集合。

(我知道这只是因为我可以一步完成它,并不意味着我应该这样做,因为可读性可能会受到影响,但我很好奇。)

谢谢!

2 个答案:

答案 0 :(得分:12)

您可以通过将mapping收集器传递到groupingBy收集器来简化代码,如下所示:

Map<A, Set<B>> collect = 
       listOfPairs.stream()
                  .collect(Collectors.groupingBy(Pair::getLeft, 
                                Collectors.mapping(Pair::getRight,
                                       Collectors.toSet())));

答案 1 :(得分:2)

您可以使用Map.computeIfAbsent执行此操作:

Map<A, Set<B>> finalResult = new HashMap<>();
listOfPairs.forEach(pair -> finalResult.computeIfAbsent(
        pair.getLeft(), 
        k -> new HashSet<>())
    .add(pair.getRight()));

如果您想保留广告订单,可以分别使用LinkedHashMapLinkedHashSet代替HashMapHashSet