I have two Java Stream<String>
A
and B
.
How can I, at each step, given a predicate p
, pick an element from either A
or B
? The element that has not been picked has to stay at the head of the stream so it can be picked at the next try.
I have two Java Stream<String>
A
and B
.
How can I, at each step, given a predicate p
, pick an element from either A
or B
? The element that has not been picked has to stay at the head of the stream so it can be picked at the next try.
Use can use a zip
method. The standard library doesn't include one as standard, but you can just copy the source shown below (from this question).
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
class Main {
public static void main(String[] args) {
List<String> list1 = Arrays.asList("a1", "a2", "a3");
List<String> list2 = Arrays.asList("b1", "b2", "b3");
BiFunction<String, String, String> picker = (a, b) -> {
// pick whether you want a from list1, or b from list2
return a;
};
List<String> result =
StreamUtils.zip(list1.stream(), list2.stream(), picker)
.collect(Collectors.toList());
System.out.println(result);
}
}
import java.util.Objects;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import java.util.function.BiFunction;
public class StreamUtils {
public static<A, B, C> Stream<C> zip(Stream<? extends A> a,
Stream<? extends B> b,
BiFunction<? super A, ? super B, ? extends C> zipper) {
Objects.requireNonNull(zipper);
Spliterator<? extends A> aSpliterator = Objects.requireNonNull(a).spliterator();
Spliterator<? extends B> bSpliterator = Objects.requireNonNull(b).spliterator();
// Zipping looses DISTINCT and SORTED characteristics
int characteristics = aSpliterator.characteristics() & bSpliterator.characteristics() &
~(Spliterator.DISTINCT | Spliterator.SORTED);
long zipSize = ((characteristics & Spliterator.SIZED) != 0)
? Math.min(aSpliterator.getExactSizeIfKnown(), bSpliterator.getExactSizeIfKnown())
: -1;
Iterator<A> aIterator = Spliterators.iterator(aSpliterator);
Iterator<B> bIterator = Spliterators.iterator(bSpliterator);
Iterator<C> cIterator = new Iterator<C>() {
@Override
public boolean hasNext() {
return aIterator.hasNext() && bIterator.hasNext();
}
@Override
public C next() {
return zipper.apply(aIterator.next(), bIterator.next());
}
};
Spliterator<C> split = Spliterators.spliterator(cIterator, zipSize, characteristics);
return (a.isParallel() || b.isParallel())
? StreamSupport.stream(split, true)
: StreamSupport.stream(split, false);
}
}
If the two input streams are already sorted by the merge function, the new stream will be sorted by the merge function eventually. It's going to be something like merge sort. So you just need to concat the two streams, sorted then.
final Stream<String> a = Stream.of("a", "b", "c");
final Stream<String> b = Stream.of("1", "2", "3");
Stream.concat(a, b).sorted((a, b) -> mergeFunction /* TODO */);
Otherwise, probably you will need the stream API in abacus-common:
final Stream<String> a = Stream.of("a", "b", "c");
final Stream<String> b = Stream.of("1", "2", "3");
Stream.merge(a, b, mergeFunction);