Ruby的最佳方式是做my_array.select(n){ |elem| ... }
之类的事情,其中n
表示“我只想要返回n
个元素,并在达到该数字后停止评估”?< / p>
答案 0 :(得分:2)
这应该可以解决问题:
my_array.select(n) { |elem| elem.meets_condition? }.take(n)
但是,这仍将评估所有项目。
如果你有一个懒惰的枚举器,你可以以更有效的方式做到这一点。
https://github.com/ruby/ruby/pull/100显示尝试启用此功能。
答案 1 :(得分:2)
您可以轻松实施lazy_select
:
module Enumerable
def lazy_select
Enumerator.new do |yielder|
each do |e|
yielder.yield(e) if yield(e)
end
end
end
end
然后像
(1..10000000000).to_enum.lazy_select{|e| e % 3 == 0}.take(3)
# => [3, 6, 9]
立即执行。
答案 2 :(得分:1)
如果你使用股票1.8.7或1.9.2 ......
,看起来没有避免传统的循环result = []
num_want = 4
i = 0
while (elem = my_array[i]) && my_array.length < num_want
result << elem if elem.some_condition
i += 1
end
答案 3 :(得分:1)
你可以创建一个类似Enumerable的扩展,它具有你想要的selectn语义:
module SelectN
def selectn(n)
out = []
each do |e|
break if n <= 0
if yield e
out << e
n -= 1
end
end
out
end
end
a = (0..9).to_a
a.select{ |e| e%3 == 0 } # [0, 3, 6, 9]
a.extend SelectN
a.selectn(1) { |e| e%3 == 0 } # [0]
a.selectn(3) { |e| e%3 == 0 } # [0, 3, 6]
# for convenience, you could inject this behavior into all Arrays
# the usual caveats about monkey-patching std library behavior applies
class Array; include SelectN; end
(0..9).to_a.selectn(2) { |e| e%3 == 0 } # [0,3]
(0..9).to_a.selectn(99) { |e| e%3 == 0 } # [0,3, 6, 9]
答案 4 :(得分:0)
我猜破坏的循环可以用break
或类似的东西以老式的循环风格完成:
n = 5
[1,2,3,4,5,6,7].take_while { |e| n -= 1; n >= 0 && e < 7 }
在函数式语言中,这将是递归,但没有TCO,它在Ruby中没有多大意义。
<强>更新强>
dbenhur指出, take_while
是一个愚蠢的想法,所以我不知道什么比循环更好。
答案 5 :(得分:0)
为什么不在#select:
之前翻转它并执行#takemy_array.take(n).select { |elem| ... }
这将确保您只对n
个项目进行计算。
修改强>
Enumerable :: Lazy已知速度较慢,但如果您的计算计算成本比懒惰慢,则可以使用Ruby 2.0功能:
my_array.lazy.select { |elem| ... }.take(n)
请参阅:http://blog.railsware.com/2012/03/13/ruby-2-0-enumerablelazy/