如何在没有迭代器的情况下在Ruby中收集块值?

时间:2017-02-28 23:13:55

标签: ruby

以下是一些代码:

i = 0
collection = []
loop do
  i += 1
  break if complicated_predicate_of(i)
  collection << i
end
collection

我事先并不知道有多少次我需要迭代;这取决于complicated_predicate_of(i)。我可以做0.upto(Float::INFINITY).times.collect do ... end之类的事,但这很丑陋。

我想这样做:

i = 0
collection = loop.collect do
  i += 1
  break if complicated_predicate_of(i)
  i
end

但是,虽然由于某些原因它不是语法错误,loop.collect似乎没有收集任何东西。 (loop.reduce)也没有。声明结束时collection为零。

换句话说,我想在没有显式迭代器的情况下收集loop语句的值。有没有办法实现这个目标?

2 个答案:

答案 0 :(得分:3)

你可以写

collection = 1.step.take_while do |i| 
  i <= 3 # this block needs to return *false* to stop the taking
end

无论您最终选择哪种解决方案,请记住您始终可以选择引入具有不言自明名称的帮助方法。特别是如果您需要在源代码的许多地方收集这样的数字。

假设您想要隐藏上面解决方案的错综复杂的内容,那么这可能是您的帮助方法:

def numbers_until(&block)
  i = 0
  collection = []
  loop do
    i += 1
    break if yield i
    collection << i
  end
  collection
end

collection = numbers_until do |i|
   i > 3 # this block needs to return *true* to stop the taking
end

答案 1 :(得分:2)

你可以写

def complicated_predicate_of(i)
  i > 3
end

1.step.with_object([]) { |i,collection| complicated_predicate_of(i) ?
  (break collection) : collection << i }
  #=> [1, 2, 3]