How to interleave (merge) two Java 8 Streams?

  • A+
Category:Languages
 Stream<String> a = Stream.of("one", "three", "five");  Stream<String> b = Stream.of("two", "four", "six"); 

What do I need to do for the output to be the below?

// one // two // three // four // five // six 

I looked into concat but as the javadoc explains, it just appends one after the other, it does not interleave / intersperse.

Stream<String> out = Stream.concat(a, b); out.forEach(System.out::println); 

Creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.

Wrongly gives

 // one  // three  // five  // two  // four  // six 

Could do it if I collected them and iterated, but was hoping for something more Java8-y, Streamy :-)

Note

I don't want to zip the streams

“zip” operation will take an element from each collection and combine them.

the result of a zip operation would be something like this: (unwanted)

 // onetwo  // threefour  // fivesix 

 


I’d use something like this:

public static <T> Stream<T> interleave(Stream<T> a, Stream<T> b) {     Spliterator<T> spA = a.spliterator(), spB = b.spliterator();     long s = spA.estimateSize() + spB.estimateSize();     if(s < 0) s = Long.MAX_VALUE;     int ch = spA.characteristics() & spB.characteristics()            & (Spliterator.NONNULL|Spliterator.SIZED);     ch |= Spliterator.ORDERED;      return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(s, ch) {         Spliterator<T> sp1 = spA, sp2 = spB;          @Override         public boolean tryAdvance(Consumer<? super T> action) {             Spliterator<T> sp = sp1;             if(sp.tryAdvance(action)) {                 sp1 = sp2;                 sp2 = sp;                 return true;             }             return sp2.tryAdvance(action);         }     }, false); } 

It retains the characteristics of the input streams as far as possible, which allows certain optimizations (e.g. for count()and toArray()). Further, it adds the ORDERED even when the input streams might be unordered, to reflect the interleaving.

When one stream has more elements than the other, the remaining elements will appear at the end.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: