【问题标题】:Java8 : how to aggregate objects from a stream?Java8:如何从流中聚合对象?
【发布时间】:2015-11-23 10:36:51
【问题描述】:

编辑

恕我直言:我认为这不是重复的,因为这两个问题试图以不同的方式解决问题,特别是因为它们提供了完全不同的技术技能(最后,因为我问自己这两个问题)。

问题

如何从有序流中聚合项目,最好是在中间操作中?

上下文

在我的另一个问题之后:Java8 stream lines and aggregate with action on terminal line

我有一个非常大的表格文件:

MASTER_REF1
    SUBREF1
    SUBREF2
    SUBREF3
MASTER_REF2
MASTER_REF3
    SUBREF1
    ...

SUBREF(如果有的话)适用于 MASTER_REF 并且两者都是复杂对象(您可以想象它有点 JSON)。

乍一看,我尝试使用在聚合时返回 null 的操作和可以找到一组行时的值(如果 line.charAt(0)!=' ' 结束一个“组”行)来对行进行分组。

此代码难以阅读,需要.filter(Objects::nonNull)

我认为可以使用.collect(groupingBy(...)).reduce(...) 来实现这一点,但这些是终端操作:

  • 在我的情况下不需要:行是有序的,应该按它们的位置分组,然后转换行组(map+filter+...+foreach);
  • 也不是一个好主意:我说的是一个比 RAM+SWAP 总量大得多的巨大数据文件......终端操作会使可用资源饱和(如前所述,我需要保留组在内存中,因为之后会被转化)

【问题讨论】:

  • 你的other question有什么区别?
  • @Tunaki 我的问题可以通过两种方式解决:通过更好的设计(例如聚合器;这个问题)或通过为我提供一种对我丑陋的设计执行“假最后一行”操作的方法(上一个问题)。由于两者都非常不同,并且两者都可以在不同的用例中重复使用,我认为两者都应该得到自己的答案。顺便说一句,如果这是一个真正的副本,我就不会花时间写两个问题并将它们交叉链接

标签: java java-8 java-stream


【解决方案1】:

正如我在上一个问题的answer 中已经指出的那样,可以使用一些提供部分归约操作的第三方库。我自己开发的StreamEx 就是其中之一。

在 StreamEx 库中,部分归约操作是在满足某些条件时组合多个输入元素的中间流操作。通常条件是通过 BiPredicate 应用于相邻的流元素对指定的,当元素应该组合在一起时返回 true。组合元素最简单的方法是通过StreamEx.groupRuns() 方法创建一个List,如下所示:

Stream<List<String>> records = StreamEx.of(Files.lines(path))
    .groupRuns((line1, line2) -> !line2.startsWith("MASTER"));

在这里,当两个相邻行中的第二行以 "MASTER" 开头时,我们开始一个新记录(如您的示例所示)。否则我们继续之前的记录。

请注意,这样的流仍然是惰性的。在顺序处理中,一次最多创建一个中间List&lt;String&gt;。也支持并行处理,尽管将Files.lines 流转换为并行模式很少能提高性能(至少在 Java-9 之前是这样)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-24
    • 1970-01-01
    • 2016-10-26
    • 1970-01-01
    • 2020-03-19
    • 1970-01-01
    相关资源
    最近更新 更多