问题“产量一词的含义”提到了Enumerator::Yielder#yield
方法。我以前没用过,想知道在什么情况下它会有用。
当您想创建无限的项目列表(例如埃拉托色尼筛)以及需要使用外部迭代器时,它主要有用吗?
问题“产量一词的含义”提到了Enumerator::Yielder#yield
方法。我以前没用过,想知道在什么情况下它会有用。
当您想创建无限的项目列表(例如埃拉托色尼筛)以及需要使用外部迭代器时,它主要有用吗?
“如何创建 Times 的无限枚举? ”谈到构造和惰性迭代器,但我最喜欢的用法是用附加功能包装现有的 Enumerable(任何可枚举,无需知道它到底是什么,它是否是无限的等等) .
一个简单的例子是实现该each_with_index
方法(或更一般地说,with_index
方法):
module Enumerable
def my_with_index
Enumerator.new do |yielder|
i = 0
self.each do |e|
yielder.yield e, i
i += 1
end
end
end
def my_each_with_index
self.my_with_index.each do |e, i|
yield e, i
end
end
end
[:foo, :bar, :baz].my_each_with_index do |e,i|
puts "#{i}: #{e}"
end
#=>0: foo
#=>1: bar
#=>2: baz
扩展到核心库中尚未实现的东西,例如从给定数组循环分配值给每个可枚举元素(例如,用于着色表行):
module Enumerable
def with_cycle values
Enumerator.new do |yielder|
self.each do |e|
v = values.shift
yielder.yield e, v
values.push v
end
end
end
end
p (1..10).with_cycle([:red, :green, :blue]).to_a # works with any Enumerable, such as Range
#=>[[1, :red], [2, :green], [3, :blue], [4, :red], [5, :green], [6, :blue], [7, :red], [8, :green], [9, :blue], [10, :red]]
重点是这些方法返回一个Enumerator
,然后您将其与通常的 Enumerable 方法(例如select
、map
等)结合使用inject
。
由于 Mladen 提到要获得其他答案,我想我会举一个我今天早些时候在编写一个将从多个物理设备接收数据、分析数据并连接相关数据(我们从多个设备看到)的应用程序时所做的事情的例子. 这是一个长期运行的应用程序,如果我从不丢弃数据(例如,至少有一天没有更新),那么它会变得无限大。
在过去,我会做这样的事情:
delete_old_stuff if rand(300) == 0
并使用随机数完成此操作。然而,这并不是纯粹的确定性。我知道它将大约每 300 次评估(即秒)运行一次,但不会每 300 次运行一次。
我之前写的是这样的:
counter = Enumerator.new do |y|
a = (0..300)
loop do
a.each do |b|
y.yield b
end
delete_old_stuff
end
end
我可以delete_old_stuff if rand(300) == 0
用counter.next
现在,我确信有一种更有效或预先制作的方法可以做到这一点,但是被Enumerator::Yielder#yield
你的问题和链接的问题所激发,这就是我想出的。
例如,您可以使用它内联构造 Rack 响应主体,而无需创建类。AnEnumerator
也可以“由外而内”工作 - 您调用Enumerator#each
which 调用next
枚举器并按顺序返回每个值。例如,您可以让 Rack 响应主体返回一系列数字:
run ->(env) {
body = Enumerator.new do |y|
9.times { |i| y.yield(i.to_s) }
end
[200, {'Content-Length' => '9'}, body]
}
当您有多个要枚举的对象时,它似乎很有用,但 flat_map 不适合,并且您想将枚举与另一个操作链接起来:
module Enumerable
def count_by
items_grouped_by_criteria = group_by {|object| yield object}
counts = items_grouped_by_criteria.map{|key, array| [key, array.length]}
Hash[counts]
end
end
def calculate_letter_frequencies
each_letter.count_by {|letter| letter}
end
def each_letter
filenames = ["doc/Quickstart", "doc/Coding style"]
# Joining the text of each file into a single string would be memory-intensive
enumerator = Enumerator.new do |yielder|
filenames.each do |filename|
text = File.read(filename)
text.chars.each {|letter| yielder.yield(letter)}
end
end
enumerator
end
calculate_letter_frequencies