【问题标题】:Grouping Java8 stream without collecting it分组 Java8 流而不收集它
【发布时间】:2016-12-25 02:28:57
【问题描述】:

Java 8 中是否有任何方法可以将 java.util.stream.Stream 中的元素分组而不收集它们?我希望结果再次成为Stream。因为我必须处理大量数据甚至无限流,所以我无法先收集数据并再次流式传输结果。

所有需要分组的元素在第一个流中都是连续的。因此,我喜欢保持流评估惰性。

【问题讨论】:

  • 如果您的数据已经“预先分组”(通过连续),为什么还需要分组形式?提供一些上下文可能有助于为这个问题提供更好的答案
  • 你的意思是使用Collectors中的groupBy而不收集?
  • 听起来像是队列的工作,而不是流。消耗队列中的连续元素,直到检测到下一个组的开始,将该组添加到包含该组的下一个队列。
  • 我必须从一个流开始,因为我以这种方式获取数据(大多数时候,但并不总是在数据库中进行 JOIN 之后,但并不总是超出 jOOQ grin)和与消费者对象的合同也是一个流。我必须对数据进行分组以重新创建由连接表表示的两个实体的 1:n 关系。因此,我试图实现的是根据关系 1 侧的相同对象对数据库记录进行分组。在进一步的步骤中,我会将分组记录映射到此对象以及关系 n 侧的对象列表。

标签: java java-8 grouping java-stream


【解决方案1】:

使用标准 Stream API 无法做到这一点。一般来说,您不能这样做,因为将来总有可能出现属于任何已创建组的新项目,因此在处理所有输入之前,您无法将您的组传递给下游分析。

但是,如果您事先知道要分组的项目在输入流中总是相邻的,您可以使用增强 Stream API 的第三方库来解决您的问题。其中一个库是StreamEx,它是免费的,由我编写。它包含许多“部分归约”运算符,这些运算符根据某些谓词将相邻项折叠成单个项。通常你应该提供一个BiPredicate 来测试两个相邻的项目,如果它们应该组合在一起,则返回true。下面列出了一些部分归约操作:

  • collapse(BiPredicate):用组的第一个元素替换每个组。例如,collapse(Objects::equals) 可用于从流中删除相邻的重复项。
  • groupRuns(BiPredicate):用组元素列表替换每个组(因此StreamEx<T> 转换为StreamEx<List<T>>)。例如,stringStream.groupRuns((a, b) -> a.charAt(0) == b.charAt(0)) 将创建字符串列表流,其中每个列表包含以相同字母开头的相邻字符串。

其他部分归约操作包括intervalMaprunLengths()等。

所有部分归约操作都是惰性的、对并行友好且非常高效。

请注意,您可以使用 StreamEx.of(stream) 从常规 Java 8 流轻松构造 StreamEx 对象。还有一些方法可以从数组、Collection、Reader 等构造它。StreamEx 类实现了Stream 接口,并且与标准 Stream API 100% 兼容。

【讨论】:

  • 我去看看你的图书馆。这似乎正是我所需要的。谢谢你的建议。
  • 嗯,很有趣。很高兴看到这应用于 OP 的实际代码,@MatthiasWimmer
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-10
  • 1970-01-01
  • 2019-11-06
  • 1970-01-01
  • 2021-01-04
  • 2015-08-24
  • 2017-12-30
相关资源
最近更新 更多