14

问题“产量一词的含义”提到了Enumerator::Yielder#yield方法。我以前没用过,想知道在什么情况下它会有用。

当您想创建无限的项目列表(例如埃拉托色尼筛)以及需要使用外部迭代器时,它主要有用吗?

4

4 回答 4

11

如何创建 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 方法(例如selectmap等)结合使用inject

于 2011-02-22T00:23:01.587 回答
1

由于 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) == 0counter.next

现在,我确信有一种更有效或预先制作的方法可以做到这一点,但是被Enumerator::Yielder#yield你的问题和链接的问题所激发,这就是我想出的。

于 2011-02-26T20:40:08.153 回答
1

例如,您可以使用它内联构造 Rack 响应主体,而无需创建类。AnEnumerator也可以“由外而内”工作 - 您调用Enumerator#eachwhich 调用next枚举器并按顺序返回每个值。例如,您可以让 Rack 响应主体返回一系列数字:

run ->(env) {
  body = Enumerator.new do |y|
   9.times { |i| y.yield(i.to_s) }
  end
  [200, {'Content-Length' => '9'}, body]
}
于 2018-01-31T01:13:35.993 回答
0

当您有多个要枚举的对象时,它似乎很有用,但 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
于 2012-03-28T01:26:18.937 回答