Ruby有很多很好的迭代方法,可以直接返回结果。这主要涉及数组方法。例如:
def ten_times_tables
(1..5).map { |i| i * 10 }
end
ten_times_tables # => [10, 20, 30, 40, 50]
但是,我有时想使用while
进行迭代并直接返回结果数组。例如,数组的内容可能取决于预期的最终值或某些累加器,甚至取决于我们无法控制的条件。
(设计)示例可能如下所示:
def fibonacci_up_to(max_number)
sequence = [1, 1]
while sequence.last < max_number
sequence << sequence[-2..-1].reduce(:+)
end
sequence
end
fibonacci_up_to(5) # => [1, 1, 2, 3, 5]
对我来说,这种方法感觉非常“非Ruby”#34;我构造,命名,然后返回一个数组的事实感觉就像一个反模式。到目前为止,我能想到的最好的是使用tap
,但它仍然感觉非常icky(并且非常嵌套):
def fibonacci_up_to(max_number)
[1, 1].tap do |sequence|
while sequence.last < max_number
sequence << sequence[-2..-1].reduce(:+)
end
end
end
有没有其他人对此类问题有任何更聪明的解决方案?
答案 0 :(得分:5)
你可能想要在这种情况下寻找的东西(虽然你的人为设计的例子比你的实际用例更适合这种情况)正在创建一个Enumerator
,所以你设想的例子变成:
来自初始化的文档:
fib = Enumerator.new do |y| a = b = 1 loop do y << a a, b = b, a + b end end
然后调用它:
p fib.take_while { |elem| elem <= 5 }
#=> [1, 1, 2, 3, 5]
所以,你创建一个枚举器来迭代你的所有值,然后一旦你有了它,你可以迭代它并以任何常用的Ruby-ish方式收集你想要的数组值
答案 1 :(得分:0)
与Simple Lime的Enumerator解决方案类似,您可以编写一个在Enumerator中包装自身的方法:
def fibonacci_up_to(max_number)
return enum_for(__callee__, max_number) unless block_given?
a = b = 1
while a <= max_number
yield a
a, b = b, a + b
end
end
fibonacci_up_to(5).to_a # => [1, 1, 2, 3, 5]
这与从方法返回Enumerator实例的结果相同,但它看起来更好,您可以使用yield
关键字而不是yielder
块变量。它还可以让你做一些整洁的事情:
fibonacci_up_to(5) do |i|
# ..
end