如何打破地图/收集和返回已收集到的东西?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (15)

用代码重写这个问题:

many = 1000

# An expensive method.
#
# It returns some data or nil if no result is available.
expensive_method = lambda do
  rand(5) == 0 ? nil : "foo"
end

# Now, let's collect some data and stop collecting when no more data is
# available.

# This is concise but doesn't work.
collection = many.times.map do
  expensive_method.call || break
end

puts collection.is_a? Array # false

# This is less concise but works.
collection = []
many.times do
  collection << (expensive_method.call || break)
end

puts collection.is_a? Array # true

# My inner Rubyist ponders: Is it possible to accomplish this more concisely
# using map?
提问于
用户回答回答于

如果你的意思是“直到休息”,[0,1,2,1,0]应导致[0,1],不是[0,1,1,0],在Ruby中,我所知道的唯一方法就是break在一个循环中。功能方法可能要慢得多,因为您实际上并没有破坏:

r = 
  [0,1,2,1,0].inject([true, []]) do |(f, a), i|
    if f
      if i > 1
        [false, a]
      else
        [f, a << i]
      end
    else
      [f, a]
    end
  end
puts r.last.inspect

与:

r = []
[0,1,2,1,0].each do |i|
  break if i > 1
  r << i
end
puts r.inspect

对于Ruby来说,尾递归是不可能的,这就是在真正的函数语言中是如何做到的。

破断map不适合我,结果是nil

附加:@dogen朋k指出,take_while(和drop_while实际上,这可能是一个更好的选择,只是它总是创建临时数组,这可能是一个问题,也可能不是问题。

用户回答回答于

当然,在Ruby中这样做的唯一方法是一个过滤器类型的方法,然后将结果传递给映射。我不确定这在1.8是否有效,但在1.9你可以:

[0,1,2,1,0].take_while {|val| val < 2}.map(&:some_function)

或在times

3.times.take_while {|count| count <= 1 } #=> [0,1]

扫码关注云+社区