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?
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)