Ruby #select,但只选择一定数量

时间:2012-03-27 21:02:46

标签: ruby select

Ruby的最佳方式是做my_array.select(n){ |elem| ... }之类的事情,其中​​n表示“我只想要返回n个元素,并在达到该数字后停止评估”?< / p>

6 个答案:

答案 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:

之前翻转它并执行#take
my_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/