为了更好地理解Ruby Fibers和Enumerators,我编写了一个小程序来生成前10个素数回文。 (我没有实现Eratosthenes的筛子或使用Ruby的Prime模块;我想专注于生成器和过滤器。)
我的第一个版本使用光纤来生成素数,并使用枚举器来过滤回文:
module PrimeSeries
extend self
def generator
Fiber.new do
Fiber.yield(2)
3.step(by: 2) { |n| Fiber.yield(n) if prime?(n) }
end
end
def prime?(n)
return false if n < 2
return false if n > 2 && n.even?
sqrt = Math.sqrt(n).ceil
(3..sqrt).step(2).none? { |i| n % i == 0 }
end
end
module Palindrome
extend self
def filter(generator)
Enumerator.new do |yielder|
loop do
n = generator.resume
yielder.yield(n) if palindrome?(n)
end
end
end
def palindrome?(n)
str = n.to_s
str == str.reverse
end
end
primes = PrimeSeries.generator
filter = Palindrome.filter(primes)
p filter.take(10)
# => [2, 3, 5, 7, 11, 101, 131, 151, 181, 191]
我真正想要的是忽略琐碎的一位数的回文。为了这样称呼它,
filter.select { |n| n.to_s.size > 1 }.take(10)
我必须将我的生成器更改为枚举器才能利用 Enumerator :: Lazy 。
module PrimeSeries
# ...
def generator
Enumerator.new do |yielder|
yielder.yield(2)
3.step(by: 2) { |n| yielder.yield(n) if prime?(n) }
end
end
# ...
end
module Palindrome
# changed "generator.resume" to "generator.next"
# otherwise the same as previous version
end
primes = PrimeSeries.generator
filter = Palindrome.filter(primes).lazy
p filter.select { |n| n.to_s.size > 1 }.take(10).force
# => [11, 101, 131, 151, 181, 191, 313, 353, 373, 383]
起初,我在调用结束时没有.force
,而我只是得到了一个懒惰的枚举器(将延迟枚举器链接到素数,过滤,选择和获取的结果)。< / p>
虽然我认为我理解它的必要性,但我找不到force
方法的任何文档(看起来它是to_a
的别名?)或者你做的情况或者不必使用它。我很好奇是否有不需要致电force
才能评估您的最终结果。