2

I have some code which returns a Stream as intended, but maybe it can be replaced with some type of lambda or stream() operation instead of exhausting the iterators in a while loop?

It is just a method that alternates elements from the streams first and second and stops when one of them runs out of elements.

public static <T>Stream<T> alternatingSequence(Stream<T> first, Stream<T> second){
        Iterator<T> iteratorFirst = first.iterator();
        Iterator<T> iteratorSecond = second.iterator();
        Stream<T> resultStream = Stream.empty();
        while (iteratorFirst.hasNext() && iteratorSecond.hasNext()){
            resultStream = Stream.concat(resultStream, Stream.of(iteratorFirst.next(), iteratorSecond.next()));
        }
        return resultStream;
    }
}
Patrick Parker
  • 4,863
  • 4
  • 19
  • 51
Serhii
  • 165
  • 1
  • 1
  • 8
  • Maybe you also include what this code is supposed to do, instead of leaving it to the reader to figure that. – GhostCat Jul 16 '18 at 14:05
  • Are you alternating the two iterators? –  Jul 16 '18 at 14:05
  • Using Java Stream API. Maybe, this code can't be replaced lambda expression? – Serhii Jul 16 '18 at 14:05
  • Just method that alternates elements from the streams first and second and stopping when one of them runs out of elements – Serhii Jul 16 '18 at 14:08
  • 1
    ah, so you intend to combine two streams (a1,a2...) and (b1,b2...) and return _alternating_ (a1, b1, a2, b2...) ? and presumably you want lazy-evaluation of next elements, am I right? – Patrick Parker Jul 16 '18 at 14:08
  • Possible duplicate of [Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip)](https://stackoverflow.com/questions/17640754/zipping-streams-using-jdk8-with-lambda-java-util-stream-streams-zip) –  Jul 16 '18 at 14:14
  • @PatrickParker Changed that long ago. –  Jul 16 '18 at 14:15
  • 2
    Something like `Stream.generate(() -> null).takewhile(iteratorFirst.hasNext() && iteratorSecond.hasNext()).flatMap(ignored -> Stream.of(iteratorFirst.next(), iteratorSecond.next()))` could do, but I don't think it's more readable than your existing solution. – Jaroslaw Pawlak Jul 16 '18 at 14:19
  • 2
    Or `StreamSupport.stream(iteratorFirst.spliterator(), false).filter(element -> iteratorSecond.hasNext()).flatMap(element -> Stream.of(element, iteratorSecond.next()))` but it again violates the contract, as the `Predicate` should be stateless. – Jaroslaw Pawlak Jul 16 '18 at 14:23
  • I must use Java8 only, so "takeWhile" is not valid method for me. How can I replace it by Java8? – Serhii Jul 17 '18 at 09:39
  • @Сергей What exactly is the output you require? – Pankaj Singhal Jul 17 '18 at 16:04
  • Stream first["A", "B", "C", "D"], Stream second["1", "2", "3"], Stream output["A", "1", "B", "2", "C", "3"], for example. – Serhii Jul 17 '18 at 19:30
  • @Сергей was your question answered successfully? – Patrick Parker Jul 28 '18 at 14:15

1 Answers1

2

Using Guava's Streams.zip you can combine the two streams into a stream of two-element streams, which you may then simply flatten to produce an alternating sequence:

return Streams.zip(first, second, (arg1, arg2) -> Stream.of(arg1, arg2))
    .flatMap(Function.identity());

One caveat is that the resulting stream is not efficiently splittable (see linked doc). This may harm parallel performance.

Note:

If you don't have access to Guava then you can implement your own zip(a, b, bifunc) as shown here.

Patrick Parker
  • 4,863
  • 4
  • 19
  • 51