我试图用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
levels
的类是一个懒惰的枚举器。我希望它包含每个环中的素数[3,2,3等] - 请参阅项目euler参考。
如果我只是从枚举器打印出来,我得到了我期望的结果:
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}]
为什么懒惰的枚举器会以这种方式工作?我将来如何预测呢?
我询问了IRC红宝石频道,没有人对它有任何想法。他们说他们在一两天前讨论过这个问题并没有得出任何结论。
一般来说,似乎必须处理它并继续前进。
答案 0 :(得分:2)
这里发生的事情是你方便地忽略了返回的结构并拔出要显示的第一个项目。在这种情况下,第一项是您生成的counts
结构。
看看这个:
levels.each do |*level|
puts level.inspect
end
这会向您显示levels
结果中的实际内容。当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 ...