从一个长流创建流

2022-01-22 00:00:00 java-8 java java-stream

我想根据 Streams 的内容将单个 Stream 拆分为 StreamsStream.生成的 Stream 应该包含原始流数据的一部分.

I want to split a single Stream into a Stream of Streams based on the contents of the Streams. The resulting the Stream should contain part of the original streams' data.

我的实际应用程序更复杂(它将时间间隔列表内的日志行分组),但我的问题是如何处理流,所以在这里我问一个简化的例子.

My real application is more complex (it is grouping log lines that are within a list of time intervals), but my problem is how to handle the streams, so here I ask about a simplified example.

我希望能够根据重复的相同数字将 Stream<Integer> 拆分为 Stream<Stream<Integer>>,只留下流奇数.

I want to be able split a Stream<Integer> into a Stream<Stream<Integer>> based on the same number being repeated, only leaving the streams with odd numbers.

例如以下流包含:

{1,1,1,2,2,2,3,6,7,7,1,1}

需要产生一个包含以下内容的流:

Would need to result in a stream of streams containing:

{{1,1,1},{3},{7,7},{1,1}}

通过过滤器开始(或结束)我可以省略偶数:

Leaving out the even numbers I can do by starting (or ending) with a filter:

Stream<Integer> input = ...;
Straem<Stream<Integer>> output = input.filter(this::isOdd).someOtherOperation();

这是不受欢迎的,因为这意味着对每个输入值进行两次评估,这是可以接受的,但我宁愿避免这样做.

This is undesired as it would mean evaluating each input value twice, this is acceptable but I would prefer avoiding this.

我当前的解决方案是遍历流的内容并创建一个 List<List<Integer>> 并将其转换为 Stream<Stream<Integer>>.然而,这意味着完整的结果保存在内存中(这对我的应用程序来说是不希望的).

My current solution does this iterating over the contents of the stream and creating a List<List<Integer>> and converting that to a Stream<Stream<Integer>>. However this means the full result is kept in memory (which is undesired for my application).

我也认为我可以通过编写自己的 Iterator 从流中读取来实现这一点,但我不确定这将如何工作.

I also think I would be able to pull this of by writing my own Iterator that reads from the stream, but I am not sure how this would work.

如何根据原始 Stream 的内容将 Stream 转换为 StreamsStream,而不首先将完整结果存储为 ListsList.

How can I convert a Stream into a Stream of Streams based on the contents of the original Stream, without storing the full result in as a List of Lists first.

推荐答案

你可能想实现你自己的 聚合拆分器 来做到这一点.proton-pack 库中已经有类似的东西(第一个链接重定向到在 proton-pack 中实现的那个)).

You may want to implement your own aggregating spliterator to do this. There's already something similar in the proton-pack library (the first link redirects to the one implemented in proton-pack).

请注意,您会得到一个 Stream<List<Integer>>(您可以尝试直接修改实现以具有 Stream<Stream<Integer>>,但您总是需要缓冲少量元素;取决于窗口的大小;以测试是否应该创建新窗口).比如:

Note that you get a Stream<List<Integer>> (you may try to modify the implementation to have a Stream<Stream<Integer>> directly, but you always need to buffer a small amount elements; depending on the window's size; to test whether you should create a new window or not). So for example:

StreamUtils.aggregate(Stream.of(1, 1, 1, 2, 2, 2, 3, 6, 7, 7, 1, 1), 
                      Objects::equals)
           .forEach(System.out::println);

输出:

[1, 1, 1]
[2, 2, 2]
[3]
[6]
[7, 7]
[1, 1]

相关文章