4

Can we somehow split stream into substreams with no more than N elements in Java? For example

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) 

splitting by two streams solution is correct only for 2 streams, the same for N streams will be very ugly and write-only.

3
  • 2
    Possible duplicate of Can you split a stream into two streams? Commented Dec 13, 2016 at 17:47
  • 1
    No, you can't, not really. Collect into actual literal collections, not streams, and it'll be doable. Commented Dec 13, 2016 at 18:58
  • 1
    This is a recurring XY Problem. Instead of asking, how to split the Stream, think about what you actually want to do with the Stream(s). Ask, how to get the desired result from the Stream, not how to split the Stream. Commented Dec 14, 2016 at 10:16

3 Answers 3

4

You can't split a Stream into 2 or more Streass easily and directly. The only way the procedural one consisting of collecting the elements to the List by the couples and mapping them back to Stream again:

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()); 

As you see it's a really long way an not worth. Wouldn't be better to store the pairs in the List rather than Stream? The API is not used for data storage but their processing.

Sign up to request clarification or add additional context in comments.

Comments

1

The JEP 485: Stream Gatherers Java 24 language feature (available as a preview language feature since Java 22) adds built-in support for partitioning a stream into lists of a given size. These lists could then be mapped into streams.

// 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); 

This uses the new Stream.gather method with the new built-in Gatherers.windowFixed gatherer to convert the initial Stream<T> to a Stream<List<T>>. This is then converted to a Stream<Stream<T>> using Stream.map with Collection::stream as the mapping function.

Javadocs

Gatherer:

An intermediate operation that transforms a stream of input elements into a stream of output elements, optionally applying a final action when the end of the upstream is reached. […]

[…]

There are many examples of gathering operations, including but not limited to: grouping elements into batches (windowing functions); de-duplicating consecutively similar elements; incremental accumulation functions (prefix scan); incremental reordering functions, etc. The class Gatherers provides implementations of common gathering operations.

Stream.gather:

Returns a stream consisting of the results of applying the given gatherer to the elements of this stream.

Gatherers.windowFixed

Returns a Gatherer that gathers elements into windows -- encounter-ordered groups of elements -- of a fixed size. If the stream is empty then no window will be produced. The last window may contain fewer elements than the supplied window size.

Example:

// 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(); 

Comments

0

For example:

<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] 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.