How to interleave (merge) two Java 8 Streams?












11















 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









share|improve this question

























  • zip is used to combine elements, I don't want to combine the elements, I want to keep the same total number of elements

    – Blundell
    Nov 14 '18 at 19:53






  • 1





    why wouldn't zip keep the same total number of elements?

    – Aomine
    Nov 14 '18 at 19:56











  • Reading the other thread, zip always takes a zipper function to combine an element from each stream to make a new element. I just want to interleave not zip

    – Blundell
    Nov 14 '18 at 19:56






  • 2





    For anyone coming here in the future, here is the comments + redirected answer : gist.github.com/blundell/3f062b8ec55fd1906c68e6ec8d848683

    – Blundell
    Nov 14 '18 at 20:13






  • 1





    I like the creation of the interleave method which essentially wraps the zip method to improve readability et al. I've voted to reopen, so you could post that here instead of externally...

    – Aomine
    Nov 14 '18 at 20:17


















11















 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









share|improve this question

























  • zip is used to combine elements, I don't want to combine the elements, I want to keep the same total number of elements

    – Blundell
    Nov 14 '18 at 19:53






  • 1





    why wouldn't zip keep the same total number of elements?

    – Aomine
    Nov 14 '18 at 19:56











  • Reading the other thread, zip always takes a zipper function to combine an element from each stream to make a new element. I just want to interleave not zip

    – Blundell
    Nov 14 '18 at 19:56






  • 2





    For anyone coming here in the future, here is the comments + redirected answer : gist.github.com/blundell/3f062b8ec55fd1906c68e6ec8d848683

    – Blundell
    Nov 14 '18 at 20:13






  • 1





    I like the creation of the interleave method which essentially wraps the zip method to improve readability et al. I've voted to reopen, so you could post that here instead of externally...

    – Aomine
    Nov 14 '18 at 20:17
















11












11








11


3






 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









share|improve this question
















 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






java-8 functional-programming java-stream






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 14 '18 at 20:01







Blundell

















asked Nov 14 '18 at 19:42









BlundellBlundell

56.9k27161193




56.9k27161193













  • zip is used to combine elements, I don't want to combine the elements, I want to keep the same total number of elements

    – Blundell
    Nov 14 '18 at 19:53






  • 1





    why wouldn't zip keep the same total number of elements?

    – Aomine
    Nov 14 '18 at 19:56











  • Reading the other thread, zip always takes a zipper function to combine an element from each stream to make a new element. I just want to interleave not zip

    – Blundell
    Nov 14 '18 at 19:56






  • 2





    For anyone coming here in the future, here is the comments + redirected answer : gist.github.com/blundell/3f062b8ec55fd1906c68e6ec8d848683

    – Blundell
    Nov 14 '18 at 20:13






  • 1





    I like the creation of the interleave method which essentially wraps the zip method to improve readability et al. I've voted to reopen, so you could post that here instead of externally...

    – Aomine
    Nov 14 '18 at 20:17





















  • zip is used to combine elements, I don't want to combine the elements, I want to keep the same total number of elements

    – Blundell
    Nov 14 '18 at 19:53






  • 1





    why wouldn't zip keep the same total number of elements?

    – Aomine
    Nov 14 '18 at 19:56











  • Reading the other thread, zip always takes a zipper function to combine an element from each stream to make a new element. I just want to interleave not zip

    – Blundell
    Nov 14 '18 at 19:56






  • 2





    For anyone coming here in the future, here is the comments + redirected answer : gist.github.com/blundell/3f062b8ec55fd1906c68e6ec8d848683

    – Blundell
    Nov 14 '18 at 20:13






  • 1





    I like the creation of the interleave method which essentially wraps the zip method to improve readability et al. I've voted to reopen, so you could post that here instead of externally...

    – Aomine
    Nov 14 '18 at 20:17



















zip is used to combine elements, I don't want to combine the elements, I want to keep the same total number of elements

– Blundell
Nov 14 '18 at 19:53





zip is used to combine elements, I don't want to combine the elements, I want to keep the same total number of elements

– Blundell
Nov 14 '18 at 19:53




1




1





why wouldn't zip keep the same total number of elements?

– Aomine
Nov 14 '18 at 19:56





why wouldn't zip keep the same total number of elements?

– Aomine
Nov 14 '18 at 19:56













Reading the other thread, zip always takes a zipper function to combine an element from each stream to make a new element. I just want to interleave not zip

– Blundell
Nov 14 '18 at 19:56





Reading the other thread, zip always takes a zipper function to combine an element from each stream to make a new element. I just want to interleave not zip

– Blundell
Nov 14 '18 at 19:56




2




2





For anyone coming here in the future, here is the comments + redirected answer : gist.github.com/blundell/3f062b8ec55fd1906c68e6ec8d848683

– Blundell
Nov 14 '18 at 20:13





For anyone coming here in the future, here is the comments + redirected answer : gist.github.com/blundell/3f062b8ec55fd1906c68e6ec8d848683

– Blundell
Nov 14 '18 at 20:13




1




1





I like the creation of the interleave method which essentially wraps the zip method to improve readability et al. I've voted to reopen, so you could post that here instead of externally...

– Aomine
Nov 14 '18 at 20:17







I like the creation of the interleave method which essentially wraps the zip method to improve readability et al. I've voted to reopen, so you could post that here instead of externally...

– Aomine
Nov 14 '18 at 20:17














5 Answers
5






active

oldest

votes


















10














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.






share|improve this answer































    2














    A much dumber solution than Holger did, but may be it would fit your requirements:



    private static <T> Stream<T> interleave(Stream<T> left, Stream<T> right) {
    Spliterator<T> splLeft = left.spliterator();
    Spliterator<T> splRight = right.spliterator();

    T single = (T) new Object[1];

    Stream.Builder<T> builder = Stream.builder();

    while (splRight.tryAdvance(x -> single[0] = x) && splLeft.tryAdvance(builder)) {
    builder.add(single[0]);
    }

    return builder.build();
    }





    share|improve this answer


























    • This inconsistently includes all elements of left, when it has more elements than right, but will drop elements of right when it has more than left. You should decide. To included all common elements, use do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder));, then decide. If you want to include all elements when the the streams have different sizes, do (splLeft.tryAdvance(builder)? splLeft: spRight).forEachRemaining(builder); after the loop. And well, Stream.Builder<T> does already implement Consumer<T>, conveniently.

      – Holger
      Nov 15 '18 at 8:26













    • @Holger indeed i wanted only common ones, but now the problem is worse, since do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder)); will still take an element from left, so it's still not correct :(. the bigger problem I see now that I think about it - is that this is cheating, Stream.Builder still uses a hidden collection to gather elements...

      – Eugene
      Nov 15 '18 at 9:16











    • Taking one additional element from left wouldn’t contradict the “interleaving” pattern (ababa). If you don’t want that, consider tracking the count and apply a limit to the resulting stream. That’s simpler than dealing with an additional storage operation, especially with generic arrays. The builder implies a storage, I thought you were aware of it, as that’s the main (only) disadvantage over implementing a spliterator.

      – Holger
      Nov 15 '18 at 9:44











    • @Holger I thought about a limit too, but don't know, the more I think about it, the more I like what you did

      – Eugene
      Nov 15 '18 at 9:46






    • 1





      @FedericoPeraltaSchaffner right, that is the exact point about the in memory collection, overall, just use whatever Holger put in place...

      – Eugene
      Nov 15 '18 at 14:44





















    2














    As you can see from the question comments, I gave this a go using zip:



    Stream<String> a = Stream.of("one", "three", "five");
    Stream<String> b = Stream.of("two", "four", "six");

    Stream<String> out = interleave(a, b);


    public static <T> Stream<T> interleave(Stream<T> streamA, Stream<T> streamB) {
    return zip(streamA, streamB, (o1, o2) -> Stream.of(o1, o2)).flatMap(s -> s);
    }

    /**
    * https://stackoverflow.com/questions/17640754/zipping-streams-using-jdk8-with-lambda-java-util-stream-streams-zip
    **/
    private static <A, B, C> Stream<C> zip(Stream<A> streamA, Stream<B> streamB, BiFunction<A, B, C> zipper) {
    final Iterator<A> iteratorA = streamA.iterator();
    final Iterator<B> iteratorB = streamB.iterator();
    final Iterator<C> iteratorC = new Iterator<C>() {
    @Override
    public boolean hasNext() {
    return iteratorA.hasNext() && iteratorB.hasNext();
    }

    @Override
    public C next() {
    return zipper.apply(iteratorA.next(), iteratorB.next());
    }
    };
    final boolean parallel = streamA.isParallel() || streamB.isParallel();
    return iteratorToFiniteStream(iteratorC, parallel);
    }

    private static <T> Stream<T> iteratorToFiniteStream(Iterator<T> iterator, boolean parallel) {
    final Iterable<T> iterable = () -> iterator;
    return StreamSupport.stream(iterable.spliterator(), parallel);
    }





    share|improve this answer































      1














      This may not be a good answer because

      (1) it collects to map, which you don't want to do I guess and

      (2) it is not completely stateless as it uses AtomicIntegers.



      Still adding it because

      (1) it is readable and

      (2) community can get an idea from this and try to improve it.



      Stream<String> a = Stream.of("one", "three", "five");
      Stream<String> b = Stream.of("two", "four", "six");

      AtomicInteger i = new AtomicInteger(0);
      AtomicInteger j = new AtomicInteger(1);

      Stream.of(a.collect(Collectors.toMap(o -> i.addAndGet(2), Function.identity())),
      b.collect(Collectors.toMap(o -> j.addAndGet(2), Function.identity())))
      .flatMap(m -> m.entrySet().stream())
      .sorted(Comparator.comparing(Map.Entry::getKey))
      .forEach(e -> System.out.println(e.getValue())); // or collect


      Output



      one
      two
      three
      four
      five
      six


      @Holger's edit



      Stream.concat(a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2), o)),
      b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2), o)))
      .sorted(Map.Entry.comparingByKey())
      .forEach(e -> System.out.println(e.getValue())); // or collect





      share|improve this answer


























      • You don’t need to collect into maps, as you are only interested in getting the stream of entries, so you can simply use Stream.concat( a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2),o)), b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2),o)) ) to get it. Then, you may chain .sorted(Map.Entry.comparingByKey()). But you’re right in that this mutable state is discouraged. Most notably, it will have problems with parallel execution.

        – Holger
        Nov 15 '18 at 8:20











      • @Holger thank you, added this to the answer. I thought about it earlier, but couldn't find an EntrySet constructor and got lazy to google search how to create an EntrySet :(

        – Kartik
        Nov 15 '18 at 23:21











      • It’s not creating an EntrySet but just a stream of Entry instances. The ready-to-use implementations are indeed not easy to find (there’s also a SimpleImmutableEntry in AbstractMap). Starting with Java 9, you can simply use Map.entry(key, value) to get an immutable Entry instance, but you have to be aware that it does not support null keys or values, so you can only use it when you can preclude null.

        – Holger
        Nov 16 '18 at 7:39



















      1














      One solution with Iterator



      final Iterator<String> iterA = a.iterator();
      final Iterator<String> iterB = b.iterator();

      final Iterator<String> iter = new Iterator<String>() {
      private final AtomicInteger idx = new AtomicInteger();
      @Override
      public boolean hasNext() {
      return iterA.hasNext() || iterB.hasNext();
      }
      @Override
      public String next() {
      return idx.getAndIncrement() % 2 == 0 && iterA.hasNext() ? iterA.next() : iterB.next();
      }
      };

      // Create target Stream with StreamEx from: https://github.com/amaembo/streamex
      StreamEx.of(iter).forEach(System.out::println);

      // Or Streams from Google Guava
      Streams.stream(iter).forEach(System.out::println);


      Or simply by the solution in abacus-util provided by me:



       AtomicInteger idx = new AtomicInteger();
      StreamEx.merge(a, b, (s1, s2) -> idx.getAndIncrement() % 2 == 0 ? Nth.FIRST : Nth.SECOND).forEach(Fn.println());





      share|improve this answer

























        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53307682%2fhow-to-interleave-merge-two-java-8-streams%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        5 Answers
        5






        active

        oldest

        votes








        5 Answers
        5






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        10














        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.






        share|improve this answer




























          10














          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.






          share|improve this answer


























            10












            10








            10







            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.






            share|improve this answer













            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.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 14 '18 at 21:05









            HolgerHolger

            164k23231439




            164k23231439

























                2














                A much dumber solution than Holger did, but may be it would fit your requirements:



                private static <T> Stream<T> interleave(Stream<T> left, Stream<T> right) {
                Spliterator<T> splLeft = left.spliterator();
                Spliterator<T> splRight = right.spliterator();

                T single = (T) new Object[1];

                Stream.Builder<T> builder = Stream.builder();

                while (splRight.tryAdvance(x -> single[0] = x) && splLeft.tryAdvance(builder)) {
                builder.add(single[0]);
                }

                return builder.build();
                }





                share|improve this answer


























                • This inconsistently includes all elements of left, when it has more elements than right, but will drop elements of right when it has more than left. You should decide. To included all common elements, use do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder));, then decide. If you want to include all elements when the the streams have different sizes, do (splLeft.tryAdvance(builder)? splLeft: spRight).forEachRemaining(builder); after the loop. And well, Stream.Builder<T> does already implement Consumer<T>, conveniently.

                  – Holger
                  Nov 15 '18 at 8:26













                • @Holger indeed i wanted only common ones, but now the problem is worse, since do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder)); will still take an element from left, so it's still not correct :(. the bigger problem I see now that I think about it - is that this is cheating, Stream.Builder still uses a hidden collection to gather elements...

                  – Eugene
                  Nov 15 '18 at 9:16











                • Taking one additional element from left wouldn’t contradict the “interleaving” pattern (ababa). If you don’t want that, consider tracking the count and apply a limit to the resulting stream. That’s simpler than dealing with an additional storage operation, especially with generic arrays. The builder implies a storage, I thought you were aware of it, as that’s the main (only) disadvantage over implementing a spliterator.

                  – Holger
                  Nov 15 '18 at 9:44











                • @Holger I thought about a limit too, but don't know, the more I think about it, the more I like what you did

                  – Eugene
                  Nov 15 '18 at 9:46






                • 1





                  @FedericoPeraltaSchaffner right, that is the exact point about the in memory collection, overall, just use whatever Holger put in place...

                  – Eugene
                  Nov 15 '18 at 14:44


















                2














                A much dumber solution than Holger did, but may be it would fit your requirements:



                private static <T> Stream<T> interleave(Stream<T> left, Stream<T> right) {
                Spliterator<T> splLeft = left.spliterator();
                Spliterator<T> splRight = right.spliterator();

                T single = (T) new Object[1];

                Stream.Builder<T> builder = Stream.builder();

                while (splRight.tryAdvance(x -> single[0] = x) && splLeft.tryAdvance(builder)) {
                builder.add(single[0]);
                }

                return builder.build();
                }





                share|improve this answer


























                • This inconsistently includes all elements of left, when it has more elements than right, but will drop elements of right when it has more than left. You should decide. To included all common elements, use do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder));, then decide. If you want to include all elements when the the streams have different sizes, do (splLeft.tryAdvance(builder)? splLeft: spRight).forEachRemaining(builder); after the loop. And well, Stream.Builder<T> does already implement Consumer<T>, conveniently.

                  – Holger
                  Nov 15 '18 at 8:26













                • @Holger indeed i wanted only common ones, but now the problem is worse, since do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder)); will still take an element from left, so it's still not correct :(. the bigger problem I see now that I think about it - is that this is cheating, Stream.Builder still uses a hidden collection to gather elements...

                  – Eugene
                  Nov 15 '18 at 9:16











                • Taking one additional element from left wouldn’t contradict the “interleaving” pattern (ababa). If you don’t want that, consider tracking the count and apply a limit to the resulting stream. That’s simpler than dealing with an additional storage operation, especially with generic arrays. The builder implies a storage, I thought you were aware of it, as that’s the main (only) disadvantage over implementing a spliterator.

                  – Holger
                  Nov 15 '18 at 9:44











                • @Holger I thought about a limit too, but don't know, the more I think about it, the more I like what you did

                  – Eugene
                  Nov 15 '18 at 9:46






                • 1





                  @FedericoPeraltaSchaffner right, that is the exact point about the in memory collection, overall, just use whatever Holger put in place...

                  – Eugene
                  Nov 15 '18 at 14:44
















                2












                2








                2







                A much dumber solution than Holger did, but may be it would fit your requirements:



                private static <T> Stream<T> interleave(Stream<T> left, Stream<T> right) {
                Spliterator<T> splLeft = left.spliterator();
                Spliterator<T> splRight = right.spliterator();

                T single = (T) new Object[1];

                Stream.Builder<T> builder = Stream.builder();

                while (splRight.tryAdvance(x -> single[0] = x) && splLeft.tryAdvance(builder)) {
                builder.add(single[0]);
                }

                return builder.build();
                }





                share|improve this answer















                A much dumber solution than Holger did, but may be it would fit your requirements:



                private static <T> Stream<T> interleave(Stream<T> left, Stream<T> right) {
                Spliterator<T> splLeft = left.spliterator();
                Spliterator<T> splRight = right.spliterator();

                T single = (T) new Object[1];

                Stream.Builder<T> builder = Stream.builder();

                while (splRight.tryAdvance(x -> single[0] = x) && splLeft.tryAdvance(builder)) {
                builder.add(single[0]);
                }

                return builder.build();
                }






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Nov 15 '18 at 10:35

























                answered Nov 15 '18 at 8:19









                EugeneEugene

                69.4k999164




                69.4k999164













                • This inconsistently includes all elements of left, when it has more elements than right, but will drop elements of right when it has more than left. You should decide. To included all common elements, use do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder));, then decide. If you want to include all elements when the the streams have different sizes, do (splLeft.tryAdvance(builder)? splLeft: spRight).forEachRemaining(builder); after the loop. And well, Stream.Builder<T> does already implement Consumer<T>, conveniently.

                  – Holger
                  Nov 15 '18 at 8:26













                • @Holger indeed i wanted only common ones, but now the problem is worse, since do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder)); will still take an element from left, so it's still not correct :(. the bigger problem I see now that I think about it - is that this is cheating, Stream.Builder still uses a hidden collection to gather elements...

                  – Eugene
                  Nov 15 '18 at 9:16











                • Taking one additional element from left wouldn’t contradict the “interleaving” pattern (ababa). If you don’t want that, consider tracking the count and apply a limit to the resulting stream. That’s simpler than dealing with an additional storage operation, especially with generic arrays. The builder implies a storage, I thought you were aware of it, as that’s the main (only) disadvantage over implementing a spliterator.

                  – Holger
                  Nov 15 '18 at 9:44











                • @Holger I thought about a limit too, but don't know, the more I think about it, the more I like what you did

                  – Eugene
                  Nov 15 '18 at 9:46






                • 1





                  @FedericoPeraltaSchaffner right, that is the exact point about the in memory collection, overall, just use whatever Holger put in place...

                  – Eugene
                  Nov 15 '18 at 14:44





















                • This inconsistently includes all elements of left, when it has more elements than right, but will drop elements of right when it has more than left. You should decide. To included all common elements, use do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder));, then decide. If you want to include all elements when the the streams have different sizes, do (splLeft.tryAdvance(builder)? splLeft: spRight).forEachRemaining(builder); after the loop. And well, Stream.Builder<T> does already implement Consumer<T>, conveniently.

                  – Holger
                  Nov 15 '18 at 8:26













                • @Holger indeed i wanted only common ones, but now the problem is worse, since do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder)); will still take an element from left, so it's still not correct :(. the bigger problem I see now that I think about it - is that this is cheating, Stream.Builder still uses a hidden collection to gather elements...

                  – Eugene
                  Nov 15 '18 at 9:16











                • Taking one additional element from left wouldn’t contradict the “interleaving” pattern (ababa). If you don’t want that, consider tracking the count and apply a limit to the resulting stream. That’s simpler than dealing with an additional storage operation, especially with generic arrays. The builder implies a storage, I thought you were aware of it, as that’s the main (only) disadvantage over implementing a spliterator.

                  – Holger
                  Nov 15 '18 at 9:44











                • @Holger I thought about a limit too, but don't know, the more I think about it, the more I like what you did

                  – Eugene
                  Nov 15 '18 at 9:46






                • 1





                  @FedericoPeraltaSchaffner right, that is the exact point about the in memory collection, overall, just use whatever Holger put in place...

                  – Eugene
                  Nov 15 '18 at 14:44



















                This inconsistently includes all elements of left, when it has more elements than right, but will drop elements of right when it has more than left. You should decide. To included all common elements, use do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder));, then decide. If you want to include all elements when the the streams have different sizes, do (splLeft.tryAdvance(builder)? splLeft: spRight).forEachRemaining(builder); after the loop. And well, Stream.Builder<T> does already implement Consumer<T>, conveniently.

                – Holger
                Nov 15 '18 at 8:26







                This inconsistently includes all elements of left, when it has more elements than right, but will drop elements of right when it has more than left. You should decide. To included all common elements, use do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder));, then decide. If you want to include all elements when the the streams have different sizes, do (splLeft.tryAdvance(builder)? splLeft: spRight).forEachRemaining(builder); after the loop. And well, Stream.Builder<T> does already implement Consumer<T>, conveniently.

                – Holger
                Nov 15 '18 at 8:26















                @Holger indeed i wanted only common ones, but now the problem is worse, since do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder)); will still take an element from left, so it's still not correct :(. the bigger problem I see now that I think about it - is that this is cheating, Stream.Builder still uses a hidden collection to gather elements...

                – Eugene
                Nov 15 '18 at 9:16





                @Holger indeed i wanted only common ones, but now the problem is worse, since do {} while(splLeft.tryAdvance(builder) && spRight.tryAdvance(builder)); will still take an element from left, so it's still not correct :(. the bigger problem I see now that I think about it - is that this is cheating, Stream.Builder still uses a hidden collection to gather elements...

                – Eugene
                Nov 15 '18 at 9:16













                Taking one additional element from left wouldn’t contradict the “interleaving” pattern (ababa). If you don’t want that, consider tracking the count and apply a limit to the resulting stream. That’s simpler than dealing with an additional storage operation, especially with generic arrays. The builder implies a storage, I thought you were aware of it, as that’s the main (only) disadvantage over implementing a spliterator.

                – Holger
                Nov 15 '18 at 9:44





                Taking one additional element from left wouldn’t contradict the “interleaving” pattern (ababa). If you don’t want that, consider tracking the count and apply a limit to the resulting stream. That’s simpler than dealing with an additional storage operation, especially with generic arrays. The builder implies a storage, I thought you were aware of it, as that’s the main (only) disadvantage over implementing a spliterator.

                – Holger
                Nov 15 '18 at 9:44













                @Holger I thought about a limit too, but don't know, the more I think about it, the more I like what you did

                – Eugene
                Nov 15 '18 at 9:46





                @Holger I thought about a limit too, but don't know, the more I think about it, the more I like what you did

                – Eugene
                Nov 15 '18 at 9:46




                1




                1





                @FedericoPeraltaSchaffner right, that is the exact point about the in memory collection, overall, just use whatever Holger put in place...

                – Eugene
                Nov 15 '18 at 14:44







                @FedericoPeraltaSchaffner right, that is the exact point about the in memory collection, overall, just use whatever Holger put in place...

                – Eugene
                Nov 15 '18 at 14:44













                2














                As you can see from the question comments, I gave this a go using zip:



                Stream<String> a = Stream.of("one", "three", "five");
                Stream<String> b = Stream.of("two", "four", "six");

                Stream<String> out = interleave(a, b);


                public static <T> Stream<T> interleave(Stream<T> streamA, Stream<T> streamB) {
                return zip(streamA, streamB, (o1, o2) -> Stream.of(o1, o2)).flatMap(s -> s);
                }

                /**
                * https://stackoverflow.com/questions/17640754/zipping-streams-using-jdk8-with-lambda-java-util-stream-streams-zip
                **/
                private static <A, B, C> Stream<C> zip(Stream<A> streamA, Stream<B> streamB, BiFunction<A, B, C> zipper) {
                final Iterator<A> iteratorA = streamA.iterator();
                final Iterator<B> iteratorB = streamB.iterator();
                final Iterator<C> iteratorC = new Iterator<C>() {
                @Override
                public boolean hasNext() {
                return iteratorA.hasNext() && iteratorB.hasNext();
                }

                @Override
                public C next() {
                return zipper.apply(iteratorA.next(), iteratorB.next());
                }
                };
                final boolean parallel = streamA.isParallel() || streamB.isParallel();
                return iteratorToFiniteStream(iteratorC, parallel);
                }

                private static <T> Stream<T> iteratorToFiniteStream(Iterator<T> iterator, boolean parallel) {
                final Iterable<T> iterable = () -> iterator;
                return StreamSupport.stream(iterable.spliterator(), parallel);
                }





                share|improve this answer




























                  2














                  As you can see from the question comments, I gave this a go using zip:



                  Stream<String> a = Stream.of("one", "three", "five");
                  Stream<String> b = Stream.of("two", "four", "six");

                  Stream<String> out = interleave(a, b);


                  public static <T> Stream<T> interleave(Stream<T> streamA, Stream<T> streamB) {
                  return zip(streamA, streamB, (o1, o2) -> Stream.of(o1, o2)).flatMap(s -> s);
                  }

                  /**
                  * https://stackoverflow.com/questions/17640754/zipping-streams-using-jdk8-with-lambda-java-util-stream-streams-zip
                  **/
                  private static <A, B, C> Stream<C> zip(Stream<A> streamA, Stream<B> streamB, BiFunction<A, B, C> zipper) {
                  final Iterator<A> iteratorA = streamA.iterator();
                  final Iterator<B> iteratorB = streamB.iterator();
                  final Iterator<C> iteratorC = new Iterator<C>() {
                  @Override
                  public boolean hasNext() {
                  return iteratorA.hasNext() && iteratorB.hasNext();
                  }

                  @Override
                  public C next() {
                  return zipper.apply(iteratorA.next(), iteratorB.next());
                  }
                  };
                  final boolean parallel = streamA.isParallel() || streamB.isParallel();
                  return iteratorToFiniteStream(iteratorC, parallel);
                  }

                  private static <T> Stream<T> iteratorToFiniteStream(Iterator<T> iterator, boolean parallel) {
                  final Iterable<T> iterable = () -> iterator;
                  return StreamSupport.stream(iterable.spliterator(), parallel);
                  }





                  share|improve this answer


























                    2












                    2








                    2







                    As you can see from the question comments, I gave this a go using zip:



                    Stream<String> a = Stream.of("one", "three", "five");
                    Stream<String> b = Stream.of("two", "four", "six");

                    Stream<String> out = interleave(a, b);


                    public static <T> Stream<T> interleave(Stream<T> streamA, Stream<T> streamB) {
                    return zip(streamA, streamB, (o1, o2) -> Stream.of(o1, o2)).flatMap(s -> s);
                    }

                    /**
                    * https://stackoverflow.com/questions/17640754/zipping-streams-using-jdk8-with-lambda-java-util-stream-streams-zip
                    **/
                    private static <A, B, C> Stream<C> zip(Stream<A> streamA, Stream<B> streamB, BiFunction<A, B, C> zipper) {
                    final Iterator<A> iteratorA = streamA.iterator();
                    final Iterator<B> iteratorB = streamB.iterator();
                    final Iterator<C> iteratorC = new Iterator<C>() {
                    @Override
                    public boolean hasNext() {
                    return iteratorA.hasNext() && iteratorB.hasNext();
                    }

                    @Override
                    public C next() {
                    return zipper.apply(iteratorA.next(), iteratorB.next());
                    }
                    };
                    final boolean parallel = streamA.isParallel() || streamB.isParallel();
                    return iteratorToFiniteStream(iteratorC, parallel);
                    }

                    private static <T> Stream<T> iteratorToFiniteStream(Iterator<T> iterator, boolean parallel) {
                    final Iterable<T> iterable = () -> iterator;
                    return StreamSupport.stream(iterable.spliterator(), parallel);
                    }





                    share|improve this answer













                    As you can see from the question comments, I gave this a go using zip:



                    Stream<String> a = Stream.of("one", "three", "five");
                    Stream<String> b = Stream.of("two", "four", "six");

                    Stream<String> out = interleave(a, b);


                    public static <T> Stream<T> interleave(Stream<T> streamA, Stream<T> streamB) {
                    return zip(streamA, streamB, (o1, o2) -> Stream.of(o1, o2)).flatMap(s -> s);
                    }

                    /**
                    * https://stackoverflow.com/questions/17640754/zipping-streams-using-jdk8-with-lambda-java-util-stream-streams-zip
                    **/
                    private static <A, B, C> Stream<C> zip(Stream<A> streamA, Stream<B> streamB, BiFunction<A, B, C> zipper) {
                    final Iterator<A> iteratorA = streamA.iterator();
                    final Iterator<B> iteratorB = streamB.iterator();
                    final Iterator<C> iteratorC = new Iterator<C>() {
                    @Override
                    public boolean hasNext() {
                    return iteratorA.hasNext() && iteratorB.hasNext();
                    }

                    @Override
                    public C next() {
                    return zipper.apply(iteratorA.next(), iteratorB.next());
                    }
                    };
                    final boolean parallel = streamA.isParallel() || streamB.isParallel();
                    return iteratorToFiniteStream(iteratorC, parallel);
                    }

                    private static <T> Stream<T> iteratorToFiniteStream(Iterator<T> iterator, boolean parallel) {
                    final Iterable<T> iterable = () -> iterator;
                    return StreamSupport.stream(iterable.spliterator(), parallel);
                    }






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Nov 15 '18 at 20:58









                    BlundellBlundell

                    56.9k27161193




                    56.9k27161193























                        1














                        This may not be a good answer because

                        (1) it collects to map, which you don't want to do I guess and

                        (2) it is not completely stateless as it uses AtomicIntegers.



                        Still adding it because

                        (1) it is readable and

                        (2) community can get an idea from this and try to improve it.



                        Stream<String> a = Stream.of("one", "three", "five");
                        Stream<String> b = Stream.of("two", "four", "six");

                        AtomicInteger i = new AtomicInteger(0);
                        AtomicInteger j = new AtomicInteger(1);

                        Stream.of(a.collect(Collectors.toMap(o -> i.addAndGet(2), Function.identity())),
                        b.collect(Collectors.toMap(o -> j.addAndGet(2), Function.identity())))
                        .flatMap(m -> m.entrySet().stream())
                        .sorted(Comparator.comparing(Map.Entry::getKey))
                        .forEach(e -> System.out.println(e.getValue())); // or collect


                        Output



                        one
                        two
                        three
                        four
                        five
                        six


                        @Holger's edit



                        Stream.concat(a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2), o)),
                        b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2), o)))
                        .sorted(Map.Entry.comparingByKey())
                        .forEach(e -> System.out.println(e.getValue())); // or collect





                        share|improve this answer


























                        • You don’t need to collect into maps, as you are only interested in getting the stream of entries, so you can simply use Stream.concat( a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2),o)), b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2),o)) ) to get it. Then, you may chain .sorted(Map.Entry.comparingByKey()). But you’re right in that this mutable state is discouraged. Most notably, it will have problems with parallel execution.

                          – Holger
                          Nov 15 '18 at 8:20











                        • @Holger thank you, added this to the answer. I thought about it earlier, but couldn't find an EntrySet constructor and got lazy to google search how to create an EntrySet :(

                          – Kartik
                          Nov 15 '18 at 23:21











                        • It’s not creating an EntrySet but just a stream of Entry instances. The ready-to-use implementations are indeed not easy to find (there’s also a SimpleImmutableEntry in AbstractMap). Starting with Java 9, you can simply use Map.entry(key, value) to get an immutable Entry instance, but you have to be aware that it does not support null keys or values, so you can only use it when you can preclude null.

                          – Holger
                          Nov 16 '18 at 7:39
















                        1














                        This may not be a good answer because

                        (1) it collects to map, which you don't want to do I guess and

                        (2) it is not completely stateless as it uses AtomicIntegers.



                        Still adding it because

                        (1) it is readable and

                        (2) community can get an idea from this and try to improve it.



                        Stream<String> a = Stream.of("one", "three", "five");
                        Stream<String> b = Stream.of("two", "four", "six");

                        AtomicInteger i = new AtomicInteger(0);
                        AtomicInteger j = new AtomicInteger(1);

                        Stream.of(a.collect(Collectors.toMap(o -> i.addAndGet(2), Function.identity())),
                        b.collect(Collectors.toMap(o -> j.addAndGet(2), Function.identity())))
                        .flatMap(m -> m.entrySet().stream())
                        .sorted(Comparator.comparing(Map.Entry::getKey))
                        .forEach(e -> System.out.println(e.getValue())); // or collect


                        Output



                        one
                        two
                        three
                        four
                        five
                        six


                        @Holger's edit



                        Stream.concat(a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2), o)),
                        b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2), o)))
                        .sorted(Map.Entry.comparingByKey())
                        .forEach(e -> System.out.println(e.getValue())); // or collect





                        share|improve this answer


























                        • You don’t need to collect into maps, as you are only interested in getting the stream of entries, so you can simply use Stream.concat( a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2),o)), b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2),o)) ) to get it. Then, you may chain .sorted(Map.Entry.comparingByKey()). But you’re right in that this mutable state is discouraged. Most notably, it will have problems with parallel execution.

                          – Holger
                          Nov 15 '18 at 8:20











                        • @Holger thank you, added this to the answer. I thought about it earlier, but couldn't find an EntrySet constructor and got lazy to google search how to create an EntrySet :(

                          – Kartik
                          Nov 15 '18 at 23:21











                        • It’s not creating an EntrySet but just a stream of Entry instances. The ready-to-use implementations are indeed not easy to find (there’s also a SimpleImmutableEntry in AbstractMap). Starting with Java 9, you can simply use Map.entry(key, value) to get an immutable Entry instance, but you have to be aware that it does not support null keys or values, so you can only use it when you can preclude null.

                          – Holger
                          Nov 16 '18 at 7:39














                        1












                        1








                        1







                        This may not be a good answer because

                        (1) it collects to map, which you don't want to do I guess and

                        (2) it is not completely stateless as it uses AtomicIntegers.



                        Still adding it because

                        (1) it is readable and

                        (2) community can get an idea from this and try to improve it.



                        Stream<String> a = Stream.of("one", "three", "five");
                        Stream<String> b = Stream.of("two", "four", "six");

                        AtomicInteger i = new AtomicInteger(0);
                        AtomicInteger j = new AtomicInteger(1);

                        Stream.of(a.collect(Collectors.toMap(o -> i.addAndGet(2), Function.identity())),
                        b.collect(Collectors.toMap(o -> j.addAndGet(2), Function.identity())))
                        .flatMap(m -> m.entrySet().stream())
                        .sorted(Comparator.comparing(Map.Entry::getKey))
                        .forEach(e -> System.out.println(e.getValue())); // or collect


                        Output



                        one
                        two
                        three
                        four
                        five
                        six


                        @Holger's edit



                        Stream.concat(a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2), o)),
                        b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2), o)))
                        .sorted(Map.Entry.comparingByKey())
                        .forEach(e -> System.out.println(e.getValue())); // or collect





                        share|improve this answer















                        This may not be a good answer because

                        (1) it collects to map, which you don't want to do I guess and

                        (2) it is not completely stateless as it uses AtomicIntegers.



                        Still adding it because

                        (1) it is readable and

                        (2) community can get an idea from this and try to improve it.



                        Stream<String> a = Stream.of("one", "three", "five");
                        Stream<String> b = Stream.of("two", "four", "six");

                        AtomicInteger i = new AtomicInteger(0);
                        AtomicInteger j = new AtomicInteger(1);

                        Stream.of(a.collect(Collectors.toMap(o -> i.addAndGet(2), Function.identity())),
                        b.collect(Collectors.toMap(o -> j.addAndGet(2), Function.identity())))
                        .flatMap(m -> m.entrySet().stream())
                        .sorted(Comparator.comparing(Map.Entry::getKey))
                        .forEach(e -> System.out.println(e.getValue())); // or collect


                        Output



                        one
                        two
                        three
                        four
                        five
                        six


                        @Holger's edit



                        Stream.concat(a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2), o)),
                        b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2), o)))
                        .sorted(Map.Entry.comparingByKey())
                        .forEach(e -> System.out.println(e.getValue())); // or collect






                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited Nov 15 '18 at 23:33

























                        answered Nov 14 '18 at 23:26









                        KartikKartik

                        2,88931333




                        2,88931333













                        • You don’t need to collect into maps, as you are only interested in getting the stream of entries, so you can simply use Stream.concat( a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2),o)), b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2),o)) ) to get it. Then, you may chain .sorted(Map.Entry.comparingByKey()). But you’re right in that this mutable state is discouraged. Most notably, it will have problems with parallel execution.

                          – Holger
                          Nov 15 '18 at 8:20











                        • @Holger thank you, added this to the answer. I thought about it earlier, but couldn't find an EntrySet constructor and got lazy to google search how to create an EntrySet :(

                          – Kartik
                          Nov 15 '18 at 23:21











                        • It’s not creating an EntrySet but just a stream of Entry instances. The ready-to-use implementations are indeed not easy to find (there’s also a SimpleImmutableEntry in AbstractMap). Starting with Java 9, you can simply use Map.entry(key, value) to get an immutable Entry instance, but you have to be aware that it does not support null keys or values, so you can only use it when you can preclude null.

                          – Holger
                          Nov 16 '18 at 7:39



















                        • You don’t need to collect into maps, as you are only interested in getting the stream of entries, so you can simply use Stream.concat( a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2),o)), b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2),o)) ) to get it. Then, you may chain .sorted(Map.Entry.comparingByKey()). But you’re right in that this mutable state is discouraged. Most notably, it will have problems with parallel execution.

                          – Holger
                          Nov 15 '18 at 8:20











                        • @Holger thank you, added this to the answer. I thought about it earlier, but couldn't find an EntrySet constructor and got lazy to google search how to create an EntrySet :(

                          – Kartik
                          Nov 15 '18 at 23:21











                        • It’s not creating an EntrySet but just a stream of Entry instances. The ready-to-use implementations are indeed not easy to find (there’s also a SimpleImmutableEntry in AbstractMap). Starting with Java 9, you can simply use Map.entry(key, value) to get an immutable Entry instance, but you have to be aware that it does not support null keys or values, so you can only use it when you can preclude null.

                          – Holger
                          Nov 16 '18 at 7:39

















                        You don’t need to collect into maps, as you are only interested in getting the stream of entries, so you can simply use Stream.concat( a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2),o)), b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2),o)) ) to get it. Then, you may chain .sorted(Map.Entry.comparingByKey()). But you’re right in that this mutable state is discouraged. Most notably, it will have problems with parallel execution.

                        – Holger
                        Nov 15 '18 at 8:20





                        You don’t need to collect into maps, as you are only interested in getting the stream of entries, so you can simply use Stream.concat( a.map(o -> new AbstractMap.SimpleEntry<>(i.addAndGet(2),o)), b.map(o -> new AbstractMap.SimpleEntry<>(j.addAndGet(2),o)) ) to get it. Then, you may chain .sorted(Map.Entry.comparingByKey()). But you’re right in that this mutable state is discouraged. Most notably, it will have problems with parallel execution.

                        – Holger
                        Nov 15 '18 at 8:20













                        @Holger thank you, added this to the answer. I thought about it earlier, but couldn't find an EntrySet constructor and got lazy to google search how to create an EntrySet :(

                        – Kartik
                        Nov 15 '18 at 23:21





                        @Holger thank you, added this to the answer. I thought about it earlier, but couldn't find an EntrySet constructor and got lazy to google search how to create an EntrySet :(

                        – Kartik
                        Nov 15 '18 at 23:21













                        It’s not creating an EntrySet but just a stream of Entry instances. The ready-to-use implementations are indeed not easy to find (there’s also a SimpleImmutableEntry in AbstractMap). Starting with Java 9, you can simply use Map.entry(key, value) to get an immutable Entry instance, but you have to be aware that it does not support null keys or values, so you can only use it when you can preclude null.

                        – Holger
                        Nov 16 '18 at 7:39





                        It’s not creating an EntrySet but just a stream of Entry instances. The ready-to-use implementations are indeed not easy to find (there’s also a SimpleImmutableEntry in AbstractMap). Starting with Java 9, you can simply use Map.entry(key, value) to get an immutable Entry instance, but you have to be aware that it does not support null keys or values, so you can only use it when you can preclude null.

                        – Holger
                        Nov 16 '18 at 7:39











                        1














                        One solution with Iterator



                        final Iterator<String> iterA = a.iterator();
                        final Iterator<String> iterB = b.iterator();

                        final Iterator<String> iter = new Iterator<String>() {
                        private final AtomicInteger idx = new AtomicInteger();
                        @Override
                        public boolean hasNext() {
                        return iterA.hasNext() || iterB.hasNext();
                        }
                        @Override
                        public String next() {
                        return idx.getAndIncrement() % 2 == 0 && iterA.hasNext() ? iterA.next() : iterB.next();
                        }
                        };

                        // Create target Stream with StreamEx from: https://github.com/amaembo/streamex
                        StreamEx.of(iter).forEach(System.out::println);

                        // Or Streams from Google Guava
                        Streams.stream(iter).forEach(System.out::println);


                        Or simply by the solution in abacus-util provided by me:



                         AtomicInteger idx = new AtomicInteger();
                        StreamEx.merge(a, b, (s1, s2) -> idx.getAndIncrement() % 2 == 0 ? Nth.FIRST : Nth.SECOND).forEach(Fn.println());





                        share|improve this answer






























                          1














                          One solution with Iterator



                          final Iterator<String> iterA = a.iterator();
                          final Iterator<String> iterB = b.iterator();

                          final Iterator<String> iter = new Iterator<String>() {
                          private final AtomicInteger idx = new AtomicInteger();
                          @Override
                          public boolean hasNext() {
                          return iterA.hasNext() || iterB.hasNext();
                          }
                          @Override
                          public String next() {
                          return idx.getAndIncrement() % 2 == 0 && iterA.hasNext() ? iterA.next() : iterB.next();
                          }
                          };

                          // Create target Stream with StreamEx from: https://github.com/amaembo/streamex
                          StreamEx.of(iter).forEach(System.out::println);

                          // Or Streams from Google Guava
                          Streams.stream(iter).forEach(System.out::println);


                          Or simply by the solution in abacus-util provided by me:



                           AtomicInteger idx = new AtomicInteger();
                          StreamEx.merge(a, b, (s1, s2) -> idx.getAndIncrement() % 2 == 0 ? Nth.FIRST : Nth.SECOND).forEach(Fn.println());





                          share|improve this answer




























                            1












                            1








                            1







                            One solution with Iterator



                            final Iterator<String> iterA = a.iterator();
                            final Iterator<String> iterB = b.iterator();

                            final Iterator<String> iter = new Iterator<String>() {
                            private final AtomicInteger idx = new AtomicInteger();
                            @Override
                            public boolean hasNext() {
                            return iterA.hasNext() || iterB.hasNext();
                            }
                            @Override
                            public String next() {
                            return idx.getAndIncrement() % 2 == 0 && iterA.hasNext() ? iterA.next() : iterB.next();
                            }
                            };

                            // Create target Stream with StreamEx from: https://github.com/amaembo/streamex
                            StreamEx.of(iter).forEach(System.out::println);

                            // Or Streams from Google Guava
                            Streams.stream(iter).forEach(System.out::println);


                            Or simply by the solution in abacus-util provided by me:



                             AtomicInteger idx = new AtomicInteger();
                            StreamEx.merge(a, b, (s1, s2) -> idx.getAndIncrement() % 2 == 0 ? Nth.FIRST : Nth.SECOND).forEach(Fn.println());





                            share|improve this answer















                            One solution with Iterator



                            final Iterator<String> iterA = a.iterator();
                            final Iterator<String> iterB = b.iterator();

                            final Iterator<String> iter = new Iterator<String>() {
                            private final AtomicInteger idx = new AtomicInteger();
                            @Override
                            public boolean hasNext() {
                            return iterA.hasNext() || iterB.hasNext();
                            }
                            @Override
                            public String next() {
                            return idx.getAndIncrement() % 2 == 0 && iterA.hasNext() ? iterA.next() : iterB.next();
                            }
                            };

                            // Create target Stream with StreamEx from: https://github.com/amaembo/streamex
                            StreamEx.of(iter).forEach(System.out::println);

                            // Or Streams from Google Guava
                            Streams.stream(iter).forEach(System.out::println);


                            Or simply by the solution in abacus-util provided by me:



                             AtomicInteger idx = new AtomicInteger();
                            StreamEx.merge(a, b, (s1, s2) -> idx.getAndIncrement() % 2 == 0 ? Nth.FIRST : Nth.SECOND).forEach(Fn.println());






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Nov 16 '18 at 18:52

























                            answered Nov 16 '18 at 18:46









                            user_3380739user_3380739

                            90868




                            90868






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53307682%2fhow-to-interleave-merge-two-java-8-streams%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                這個網誌中的熱門文章

                                Post-Redirect-Get with Spring WebFlux and Thymeleaf

                                Xamarin.form Move up view when keyboard appear

                                JBPM : POST request for execute process go wrong