Ruby lazy枚举器根据用途返回不同的对象类型

我试图用
ruby以功能方式解决
Project Euler #58.

简而言之,我创建了一个枚举器来返回每个环的角数.然后,我在枚举器上链接功能操作符.当我得到我的结果时,我发现它有不同的类,这取决于我如何使用它.

spiral = Enumerator.new do |yielder|
    n = 3
    step = 2
    loop do
        vals = n.step(nil, step).take(4)
        yielder.yield vals
        step += 2
        n = vals.last + step
    end
end

primes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113]

levels = spiral
    .lazy
    .map { |ring| ring.count { |n| primes.include? n } }    
    .with_object({:total=>1.0, :primes=>0})
    .take_while do |ring_primes, counts|
        counts[:total] += 4
        counts[:primes] += ring_primes
        (counts[:primes] / counts[:total]) > 0.5
    end

级别是一个懒惰的枚举器.我希望它包含每个环中的素数[3,2,3等] – 参见项目欧拉参考.

如果我只是从枚举器打印,我得到我期望的:

levels.each do |level|
    puts "#{level}"
end

返回:

3
2
3
1

但是如果我循环.with_index我得到一个数组结果,其中期望值是第一个成员,第二个是我的.with_object参数

levels.each.with_index do |level, ix|
    puts "#{ix}: #{level}"
end

返回:

0: [3, {:total=>5.0, :primes=>3}]
1: [2, {:total=>9.0, :primes=>5}]
2: [3, {:total=>13.0, :primes=>8}]
3: [1, {:total=>17.0, :primes=>9}]

为什么懒惰的枚举器以这种方式工作,我将来如何预测呢?

更新

我询问了IRCruby频道,没有人对它有任何想法.他们说他们在一两天前讨论过这个问题并没有得出任何结论.

一般来说,似乎必须处理它并继续前进.

最佳答案 这里发生的是你方便地忽略了返回的结构并拔出了要显示的第一个项目.在这种情况下,第一项是您生成的计数结构.

看看这个:

levels.each do |*level|
  puts level.inspect
end

这会向您显示级别结果中的实际内容.当Ruby调用lambda时,它将丢弃任何不符合块接受的参数数量的附加数据.

如果您不需要该元数据,请将其删除:

levels = spiral
  .lazy
  .map { |ring| ring.count { |n| primes.include? n } }    
  .with_object({:total=>1.0, :primes=>0})
  .take_while do |ring_primes, counts|
    counts[:total] += 4
    counts[:primes] += ring_primes
    (counts[:primes] / counts[:total]) > 0.5
  end
  .map { |r,_| r }

这消除了结果中的无关元素.

这是一种清理你的枚举器的方法:

class Spiral
  include Enumerable

  def each
    Enumerator.new do |yielder|
      n = 3
      step = 2
      loop do
        vals = n.step(nil, step).take(4)
        yielder.yield vals
        step += 2
        n = vals.last + step
      end
    end
  end
end

然后你可以创建一个:

Spiral.new.each ...
点赞