-2

Is there an elegant way to interoperate two streams?

/**
 *  e.g. add([1, -1, 5], [2, 3, 4]) -> [3, 2, 9]
 */
Stream<Integer> add(Stream<Integer> a, Stream<Integer> b)  {
    //?
}

I would hate to collect both streams to do the thing in a for-loop, just to stream the result again

Duke
  • 386
  • 2
  • 13
  • 2
    I think the operation you're looking for is called [zipping](https://guava.dev/releases/snapshot/api/docs/com/google/common/collect/Streams.html#zip-java.util.stream.Stream-java.util.stream.Stream-java.util.function.BiFunction-) – matt May 20 '22 at 06:56
  • 1
    What you are looking for is the zip operation, for which there is unfortunately no method in the standard library. See: [Bridge the Gap of Zip Operation](https://dzone.com/articles/bridge-the-gap-of-zip-operation) – Jesper May 20 '22 at 06:57
  • 1
    https://stackoverflow.com/questions/17640754/zipping-streams-using-jdk8-with-lambda-java-util-stream-streams-zip – matt May 20 '22 at 06:58
  • I didn't downvote you, but I think you've provided the best answer and crossed it out for no reason. – matt May 20 '22 at 08:14
  • 2
    The problem started before this method, at the place where you decided that a `Stream` was a good way to represent a vector. – Holger May 20 '22 at 09:39

2 Answers2

1
Stream<Integer> add(Stream<Integer> a, Stream<Integer> b)  {
   Iterator<Integer> i=a.iterator();
   return b.map(bz-> i.hasNext() ?  bz + i.next() : bz);
}
Benoit Cuvelier
  • 806
  • 7
  • 23
  • 1
    Did you try this? Is there any guarantee that 'i.hasNext()' is run sequentially with map? eg could elements 1-5 be filtered before a map call is appied? – matt May 20 '22 at 07:02
  • tried with add(Stream.of(1, 2, 3), Stream.of(4, 5, 6)).forEach(System.out::println). Works well – Benoit Cuvelier May 20 '22 at 07:05
  • I would say the filter doesn't add anything. Your example doesn't really test it since your lists have the same number of elements. If a has more elements than b then it would matter if it is called 'filter, map; filter, map' vs 'filter; filter, map, map' – matt May 20 '22 at 07:11
  • I just wrote a couple of randomly generated tests with larger a or larger b - works fine. @matt does have a point that it looks a little bit fishy though – Duke May 20 '22 at 07:17
  • you are right, edited answer – Benoit Cuvelier May 20 '22 at 07:21
0

I think this question really highlights why you probably shouldn't be doing what you're doing.

1st. You're adding three pairs of int's, and your using a Stream so you have to use Integer. That's huge overhead relative to the operation.

2nd. The concept of Stream is not limited to ordered sets of data.

For that reason collecting to a list makes sense because you're explicitly operating on a finite ordered dataset.

List<Integer> la = a.collect( Collectors.toList());
List<Integer> lb = b.collect( Collectors.toList());

Stream<Integer> result = IntStream.range( 0, la.size() ).mapToObj( 
    i -> la.get(i) && lb.get(j) 
);

It might be more stream-like to use a.iterator() instead of lists because you wouldn't be limited to finite datasets.

Iterator<Integer> ia = a.iterator();
Iterator<Integer> ib = b.iterator();

if( ! ia.hasNext() || ! ib.hasNext() ) return Stream.empty();

return Stream.iterate( 
    ia.next() + ib.next(), 
    last -> ia.hasNext() && ib.hasNext(), 
    last -> ia.next() + ib.next() );
matt
  • 10,892
  • 3
  • 22
  • 34
  • 1
    You can not combine two `boolean` values with `+`. So `ia.hasNext() + ib.hasNext()` most probably should be `ia.hasNext() && ib.hasNext()`. Your two points at the beginning of the answer are correct, but the conclusion should not be to collect into lists, but not to use Streams in the first place. – Holger May 20 '22 at 09:44