简体   繁体   English

array.select最多n个元素

[英]array.select n elements at most

Consider a Ruby array with a lot of elements. 考虑一个包含很多元素的Ruby数组。

I want to reverse iterate over the array and select the first n results for which a given block returns true. 我想对数组进行反向迭代,并选择给定块返回true的前n个结果。

Eg 例如

seniors = persons.reverse.select do |person|
  person.age > 60
end

This is okay, however it collects all seniors, instead of n seniors at most. 可以,但是它会收集所有前辈,而不是最多n个前辈。 What's the nicest way to prematurely terminate the iteration when n results has been collected? 收集了n个结果后,过早终止迭代的最佳方法是什么?

seniors = []
persons.reverse.each{ |p| 
  seniors << p if p.age > 60
  break if seniors.count >= n
}

Lazy evaluation is great because it makes possible to write this kind of code without changing the abstractions you would normally use in strict evaluation (Haskell has proved how powerful this is). 惰性评估非常有用,因为它可以编写此类代码,而无需更改通常在严格评估中通常使用的抽象(Haskell证明了这种方法的强大功能)。 Happily Ruby 2.0 will ship with some infrastructure on this regard, when that time comes you'll be able to write this: 幸运的是,Ruby 2.0将在这方面附带一些基础结构,到那时,您将可以编写以下代码:

# Ruby >= 2.0
seniors = persons.reverse.lazy.select { |person| person.age > 60 }.take(n)

For Ruby < 2.0: https://github.com/yhara/enumerable-lazy 对于Ruby <2.0: https//github.com/yhara/enumerable-lazy

You can chain take_while and each_with_object : 您可以链接take_whileeach_with_object

seniors = []
persons.take_while.each_with_object(seniors) do |e, o| 
  o << e if e.age > 60 && o.count < 1000
  o.count < 1000
end

require 'ostruct'
require 'benchmark'

persons = 1000000.times.map {|i| OpenStruct.new age: Random.rand(50..85) }

Benchmark.bm do |b|
  b.report do
    seniors = []
    persons.take_while.each_with_object(seniors) do |e, o| 
      o << e if e.age > 60 && o.count < 1000
      o.count < 1000
    end
  end
end

#=> finishes in 1-3ms on my machine

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM