我如何制作一个 ruby 枚举器来通过其他两个枚举器进行惰性迭代?
How can I make a ruby enumerator that does lazy iteration through two other enumerators?
假设我有两个枚举器,enum1
和 enum2
必须延迟迭代(因为它们有副作用)。我如何构建第三个枚举器 enum3
,其中 enum3.each{|x| x}
将 lazily return 相当于 enum1 + enum2
?
在我的实际用例中,我正在流式传输两个文件,需要流式传输连接。
这里有一些 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 }
这似乎正是我想要的;
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 }
然后在结果上调用 next,显示副作用是延迟发生的;
[5] pry(main)> concated_enum.next
hi
=> 1
[6] pry(main)> concated_enum.next
hi again
=> 2
从 Ruby 2.6 开始你可以使用 Enumerable#chain/Enumerator::Chain:
a = [1, 2, 3].lazy
b = [4, 5, 6].lazy
a.chain(b).to_a
# => [1, 2, 3, 4, 5, 6]
Enumerator::Chain.new(a, b).to_a
# => [1, 2, 3, 4, 5, 6]
假设我有两个枚举器,enum1
和 enum2
必须延迟迭代(因为它们有副作用)。我如何构建第三个枚举器 enum3
,其中 enum3.each{|x| x}
将 lazily return 相当于 enum1 + enum2
?
在我的实际用例中,我正在流式传输两个文件,需要流式传输连接。
这里有一些 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 }
这似乎正是我想要的;
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 }
然后在结果上调用 next,显示副作用是延迟发生的;
[5] pry(main)> concated_enum.next
hi
=> 1
[6] pry(main)> concated_enum.next
hi again
=> 2
从 Ruby 2.6 开始你可以使用 Enumerable#chain/Enumerator::Chain:
a = [1, 2, 3].lazy
b = [4, 5, 6].lazy
a.chain(b).to_a
# => [1, 2, 3, 4, 5, 6]
Enumerator::Chain.new(a, b).to_a
# => [1, 2, 3, 4, 5, 6]