Search code examples
rubyenumeratorlazy-sequences

How can I make a ruby enumerator that does lazy iteration through two other enumerators?


Let's say I have two enumerators, enum1 and enum2 that must be lazily iterated through (because they have side effects). How do I construct a third enumerator enum3 where enum3.each{|x| x} would lazily return the equivalent of enum1 + enum2?

In my real world use case, I'm streaming in two files, and need to stream out the concatenation.


Solution

  • This seems to work just how I want;

    enums.lazy.flat_map{|enum| enum.lazy }
    

    Here's the demonstration. Define these yielding methods with side-effects;

    def test_enum
      return enum_for __method__ unless block_given?
      puts 'hi'
      yield 1
      puts 'hi again'
      yield 2
    end  
    
    def test_enum2
      return enum_for __method__ unless block_given?
      puts :a
      yield :a
      puts :b
      yield :b
    end  
    
    concated_enum = [test_enum, test_enum2].lazy.flat_map{|en| en.lazy }
    

    Then call next on the result, showing that the side effects happen lazily;

    [5] pry(main)> concated_enum.next
    hi
    => 1
    [6] pry(main)> concated_enum.next
    hi again
    => 2