2016-08-09 13 views
4

Предположим, у меня есть два счетчика, enum1 и enum2, которые должны быть лениво повторены (потому что у них есть побочные эффекты). Как создать третий счетчик enum3, где enum3.each{|x| x} будет lazily вернуть эквивалент enum1 + enum2?Как я могу сделать рубиновый перечислитель, который выполняет ленивую итерацию через два других счетчика?

В моем истинном случае использования, я транслируюсь в двух файлах, и мне нужно выпустить конкатенацию.

ответ

5

Это кажется работайте так, как я хочу;

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

Это демонстрация. Определите эти методы получения с побочными эффектами;

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 } 

Затем вызовите следующий результат, показывая, что побочные эффекты происходят лениво;

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

Большое спасибо за решение 'flat_map'. Даже если мы уже проверили ленивость «flat_map», это нам не приходило, чтобы использовать его как ленивое приложение! :) –

+0

Недостатком этого решения является то, что 'concated_enum.size' всегда возвращает' nil'. – skalee

+0

@skalee Я думаю, что это недостаток ленивых перечислений; вы никогда не узнаете, насколько они велики, пока вы не пронеслись через них. Их размер может быть функцией того, как долго вы будете выполнять итерацию. Они могут даже быть бесконечными. –

0

Вот некоторые code I wrote for fun awhile back с ленивым перечисления выброшен в:

def cat(*args) 
    args = args.to_enum 

    Enumerator.new do |yielder| 
    enum = args.next.lazy 

    loop do 
     begin 
     yielder << enum.next 
     rescue StopIteration 
     enum = args.next.lazy 
     end 
    end 
    end 
end 

Вы бы использовать его как это:

enum1 = [1,2,3] 
enum2 = [4,5,6] 
enum3 = cat(enum1, enum2) 

enum3.each do |n| 
    puts n 
end 
# => 1 
# 2 
# 3 
# 4 
# 5 
# 6 

... или просто:

cat([1,2,3],[4,5,6]).each {|n| puts n }