Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate two Java-8-Streams together [duplicate]

I'd like to iterate two Java-8-Streams together, so that I have in each iteration-step two arguments. Something like that, where somefunction produces something like Stream<Pair<A,B>>.

Stream<A> as; Stream<B> bs; somefunction (as, bs)   .forEach ((a, b) -> foo (a, b)); // or something like somefunction (as, bs)   .forEach ((Pair<A, B> abs) -> foo (abs.left (), abs.right ())); 

I want to know, if Java provides something like that, although there is no Pair in Java :-( If there is no API-Function like that, is there another way of iterating two streams simultaniously?

like image 468
F. Böller Avatar asked Jun 05 '14 12:06

F. Böller


People also ask

How do I combine two streams in Java?

concat() in Java. Stream. concat() method creates a concatenated stream in which the elements are all the elements of the first stream followed by all the elements of the second stream. The resulting stream is ordered if both of the input streams are ordered, and parallel if either of the input streams is parallel.

Can we use same stream twice?

A stream should be operated on (invoking an intermediate or terminal stream operation) only once. A stream implementation may throw IllegalStateException if it detects that the stream is being reused. So the answer is no, streams are not meant to be reused.

Is Java 8 stream faster than for loop?

Yes, streams are sometimes slower than loops, but they can also be equally fast; it depends on the circumstances. The point to take home is that sequential streams are no faster than loops.

Is streams better than for loop?

Remember that loops use an imperative style and Streams a declarative style, so Streams are likely to be much easier to maintain. If you have a small list, loops perform better. If you have a huge list, a parallel stream will perform better.


1 Answers

static <A, B> Stream<Pair<A, B>> zip(Stream<A> as, Stream<B> bs) {     Iterator<A> i=as.iterator();     return bs.filter(x->i.hasNext()).map(b->new Pair<>(i.next(), b)); } 

This does not offer parallel execution but neither did the original zip implementation.

And as F. Böller has pointed out it doesn’t work if bs is infinite and as is not. For a solution which works for all possible combinations of infinite and finite streams, an intermediate Iterator which checks both sources within the hasNext method seems unavoidable¹:

static <A, B> Stream<Pair<A,B>> zip(Stream<A> as, Stream<B> bs) {     Iterator<A> i1 = as.iterator();     Iterator<B> i2 = bs.iterator();     Iterable<Pair<A,B>> i=()->new Iterator<Pair<A,B>>() {         public boolean hasNext() {             return i1.hasNext() && i2.hasNext();         }         public Pair<A,B> next() {             return new Pair<A,B>(i1.next(), i2.next());         }     };     return StreamSupport.stream(i.spliterator(), false); } 

If you want parallel capable zipping you should consider the source of the Stream. E.g. you can zip two ArrayLists (or any RandomAccessList) like

ArrayList<Foo> l1=new ArrayList<>(); ArrayList<Bar> l2=new ArrayList<>(); IntStream.range(0, Math.min(l1.size(), l2.size()))          .mapToObj(i->new Pair(l1.get(i), l2.get(i)))          . … 

¹(unless you implement a Spliterator directly)

like image 194
Holger Avatar answered Sep 18 '22 17:09

Holger