Ruby#选择,但只选择某个数字

Ruby#选择,但只选择某个数字,ruby,select,Ruby,Select,Ruby中执行my|u数组之类的操作的最佳方法是什么?选择(n){elem|…},其中n表示“我只希望n返回元素,并在达到该数字后停止计算”这应该可以做到: my_数组。选择(n){| elem | elem.meets_条件?}。取(n) 但是,这仍将评估所有项目 如果你有一个懒惰的枚举器,你可以用一种更有效的方式 显示了启用此功能的尝试。我想可以使用break或类似于以下内容的老式循环样式来完成断开的循环: n = 5 [1,2,3,4,5,6,7].take_while { |e| n -

Ruby中执行my|u数组之类的操作的最佳方法是什么?选择(n){elem|…},其中
n
表示“我只希望
n
返回元素,并在达到该数字后停止计算”

这应该可以做到:

my_数组。选择(n){| elem | elem.meets_条件?}。取(n)

但是,这仍将评估所有项目

如果你有一个懒惰的枚举器,你可以用一种更有效的方式


显示了启用此功能的尝试。

我想可以使用
break
或类似于以下内容的老式循环样式来完成断开的循环:

n = 5
[1,2,3,4,5,6,7].take_while { |e| n -= 1; n >= 0 && e < 7 }
n=5
[1,2,3,4,5,6,7].在{e | n-=1;n>=0和&e<7}时取u
在函数式语言中,这将是递归,但如果没有TCO,它在Ruby中就没有多大意义

更新


正如dbenhur指出的那样,
take_while
是个愚蠢的主意,所以我不知道什么比循环更好。

为什么不把它翻过来,在选择之前先做“take”:

这将确保您只对
n
项目数进行计算

编辑:

Enumerable::Lazy的计算速度较慢,但如果您的计算比Lazy的计算速度慢,那么您可以使用Ruby 2.0功能:

my_array.lazy.select { |elem| ... }.take(n)

请参阅:

如果您使用的是stock 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
result=[]
num_want=4
i=0
while(elem=my_-array[i])&&my_-array.length结果您可以轻松实现
lazy\u 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] 

立即执行。

您可以创建一个类似可枚举的扩展,该扩展具有所需的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]
模块选择n
def selectn(n)
out=[]
每个都有|

如果你是对的,那就休息吧,我刚发完帖子就开始思考。我被其他几种语言中的惰性枚举所惯坏,我忘记了那个细节。我更新了我的答案以反映这一点。另请参见
。to_enum
的速度非常慢(至少在R1.8中是如此),简单循环的速度要快得多,所以懒惰的东西看起来很不错(除非您想完全重新实现它)。至少这是我试用后的印象。是的,这个懒惰的特性现在只是2.0的一部分。我不确定to|enum会有什么影响,但我可以想象它在1.9.(1..100000000)中会更好一些。to|enum.lazy.select{x | x%3==0}.take(10)。to|a在ruby 2.0中速度非常快,因为它值得。。。我想,成本的高低取决于将特定对象转换为枚举的复杂性。然后,您必须重复该操作,直到获得正确的计数。对于第一次
n
之后可能有我想要的项目的情况,这不起作用……因为这与请求的内容无关,您需要先应用
选择
,然后再
取(n)
,事实上,不是反过来。在这种情况下,您确实需要惰性枚举。这并不等同于选择{}。take(n)它将在第一个未通过条件的元素处停止获取。您还可以执行my_array.each,然后在选择num_want元素时中断(功能上完全相同,但更像ruby)
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]