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?
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.
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.
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.
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.
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 ArrayList
s (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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With