将流拆分为具有 N 个元素的子流

问题描述 投票:0回答:3

我们能否以某种方式将 Java 中的流拆分为不超过 N 个元素的子流? 例如

Stream<Integer> s = Stream.of(1,2,3,4,5);
Stream<Stream<Integer>> separated = split(s, 2);
// after that separated should contain stream(1,2), stream(3,4), stream(5)

按两个流拆分的解决方案仅适用于 2 个流,对于 N 个流来说也是如此,将非常丑陋且只写。

java java-8 java-stream
3个回答
4
投票

您无法轻松直接地将

Stream
拆分为 2 个或更多
Streas
。程序上唯一的方法是由情侣将元素收集到
List
,然后再次将它们映射回
Stream

Stream<Integer> s = Stream.of(1,2,3,4,5);
List<Integer> list = s.collect(Collectors.toList());
int size = list.size();
    
List<List<Integer>> temp = new ArrayList<>();
List<Integer> temp2 = new ArrayList<>();
    
int index = 0;
for (int i=0; i<size; i++) {
    temp2.add(list.get(i));
    if (i%2!=0) {
        temp.add(temp2);
        temp2 = new ArrayList<>();
    }
    if (i == size - 1) {
        temp.add(temp2);
    }
}
Stream<Stream<Integer>> stream = temp.stream().map(i -> i.stream());

如您所见,这是一条非常长的路,而且不值得。将这些对存储在

List
中而不是
Stream
中不是更好吗? API 不用于数据存储,而是用于数据处理。


0
投票

例如:

<T> Stream<Stream<T>> split(Stream<T> stream, int n) {
  final var it = stream.iterator();
  final Stream.Builder<Stream<T>> result = Stream.builder();
  while (it.hasNext()) {
    final Stream.Builder<T> buf = Stream.builder();
    for (int i = 0; i < n && it.hasNext(); i++) {
      buf.accept(it.next());
    }
    result.accept(buf.build());
  }
  return result.build();
}


Stream<Integer> s = Stream.of(1,2,3,4,5);
Stream<Stream<Integer>> separated = split(s, 2);
separated.map(x -> x.collect(Collectors.toList())).forEach(System.out::println);
[1, 2]
[3, 4]
[5]

0
投票

JEP 461:流收集器Java 22 预览语言功能添加了对将流分区为给定大小的列表的内置支持。然后可以将这些列表映射到流中。

// A stream containing 2 (or less) element streams: [[1, 2], [3, 4], [5]] Stream<Stream<Integer>> separated = Stream.of(1, 2, 3, 4, 5) .gather(Gatherers.windowFixed(2)) .map(Collection::stream);
这使用新的 

Stream.gather

 方法和新的内置 Gatherers.windowFixed
 收集器将初始 
Stream<T>
 转换为 
Stream<List<T>>
。然后使用 
Stream<Stream<T>>
将其转换为
Stream.map
,并将
Collection::stream
 作为映射函数。

Java文档

Gatherer


将输入元素流转换为输出元素流的中间操作,可以选择在到达上游末尾时应用最终操作。 […]

[…]

聚集操作的例子有很多,包括但不限于:将元素分组(窗口函数);对连续相似的元素进行去重;增量累加功能(前缀扫描);增量重新排序功能等。类

Gatherers

提供了常见收集操作的实现。

Stream.gather


返回一个流,其中包含将给定收集器应用于该流的元素的结果。

Gatherers.windowFixed


返回一个收集器,它将元素收集到固定大小的窗口中——遇到有序的元素组。如果流为空,则不会生成任何窗口。最后一个窗口包含的元素可能少于提供的窗口大小。

示例:

// will contain: [[1, 2, 3], [4, 5, 6], [7, 8]] List<List<Integer>> windows = Stream.of(1,2,3,4,5,6,7,8).gather(Gatherers.windowFixed(3)).toList();

    
© www.soinside.com 2019 - 2024. All rights reserved.