I have multiple Java streams of the same length, and I want to perform some operation on the corresponding elements of each stream. For e.g., add 1st elements of all stream, 2nd elements of all streams and 3rd elements of all streams and so on.
How can we do this without first reducing each of the streams?
for Minimum reproducible example, I have the following test snippet
@Test
void aggregateMultipleStreams() {
Stream<Integer> s1 = Stream.of(1, 2);
Stream<Integer> s2 = Stream.of(4, 5);
Stream<Integer> s3 = Stream.of(7, 8);
assertEquals(List.of(1 + 4 + 7, 2 + 5 + 8), aggregate(s1, s2, s3, 2));
}
I can write the aggregate
method as follows, by reducing all the streams first.
private List<Integer> aggregate(Stream<Integer> s1, Stream<Integer> s2, Stream<Integer> s3, int streamSize) {
final List<List<Integer>> reduced = Stream.of(s1, s2, s3)
.map(s -> s.collect(Collectors.toList())).collect(Collectors.toList());
return IntStream.range(0, streamSize).mapToObj(n -> IntStream.range(0, reduced.size())
.map(v -> reduced.get(v).get(n)).sum()).collect(Collectors.toList());
}
But this could be a storage hassle, if each stream contains numerous records, for N records, we need 3N storage here.
can we accomplish the addition of corresponding elements in different streams without first reduction? can we reduce multiple streams at once in Java?
After implementing @jb_dk's solution below, the solution code snippet became:
private List<Integer> aggregate(Stream<Integer> s1, Stream<Integer> s2, Stream<Integer> s3, int streamSize) {
final List<Iterator<Integer>> iterators = Stream.of(s1, s2, s3)
.map(Stream::iterator).collect(Collectors.toList());
return IntStream.range(0, streamSize).mapToObj(n -> IntStream.range(0, iterators.size())
.map(v -> iterators.get(v).next()).sum()).collect(Collectors.toList());
}