java – 是否可以在收集器分组的情况下对每个List进行操作而不创建中间映射?

我有以下代码在List上执行分组,然后对每个分组列表进行操作,然后将其转换为单个项目:

Map<Integer,List<Record>> recordsGroupedById = myList.stream()
    .collect(Collectors.groupingBy(r -> r.get("complex_id")));

List<Complex> whatIwant = recordsGroupedById.values().stream().map(this::toComplex)
    .collect(Collectors.toList());

toComplex函数如下所示:

Complex toComplex(List<Record> records);

我觉得我可以在不创建中间地图的情况下做到这一点,也许使用reduce.有任何想法吗?

输入流按照我想在流中顺序分组的元素进行排序.在正常的循环结构中,我能够确定下一组何时开始并在那时创建“复杂”.

解决方法

那么你可以避免使用Map(老实说!)并使用我的 StreamEx库在单一管道中执行所有操作:

List<Complex> result = StreamEx.of(myList)
        .sortedBy(r -> r.get("complex_id"))
        .groupRuns((r1,r2) -> r1.get("complex_id").equals(r2.get("complex_id")))
        .map(this::toComplex)
        .toList();

这里我们首先按complex_id对输入进行排序,然后使用groupRuns自定义中间操作,如果应用于两个相邻元素的给定BiPredicate返回true,则将相邻的stream元素组合到List.然后,您有一个列表流,这些列表映射到Complex对象流,最后收集到列表中.

实际上没有中间映射,groupRuns实际上是懒惰的(在顺序模式下,它一次只保留一个中间列表),它也很好地并行化.另一方面,我的测试表明,对于未排序的输入,这种解决方案比基于groupingBy的解决方案要慢,因为它涉及对整个输入进行排序.当然sortedBy(这只是排序的快捷方式(Comparator.comparing(…)))需要中间内存来存储输入.如果您的输入已经排序(或至少部分排序,因此Timsort可以快速执行),那么此类解决方案通常比groupingBy更快.

相关文章

HashMap是Java中最常用的集合类框架,也是Java语言中非常典型...
在EffectiveJava中的第 36条中建议 用 EnumSet 替代位字段,...
介绍 注解是JDK1.5版本开始引入的一个特性,用于对代码进行说...
介绍 LinkedList同时实现了List接口和Deque接口,也就是说它...
介绍 TreeSet和TreeMap在Java里有着相同的实现,前者仅仅是对...
HashMap为什么线程不安全 put的不安全 由于多线程对HashMap进...