我有以下数组:
arr = [1, 3, 2, 5, 2, 4, 2, 2, 4, 4, 2, 2, 4, 2, 1, 5]
我想要一个包含前三个奇数元素的数组。
我知道我可以这样做:
arr.select(&:odd?).take(3)
但我希望避免遍历整个数组,而是在我找到第三场比赛后返回。
我提出了以下解决方案,我认为这就是我想要的:
my_arr.each_with_object([]) do |el, memo|
memo << el if el.odd?; break memo if memo.size == 3
end
但有没有更简单/惯用的方法呢?
答案 0 :(得分:9)
lazy enumerator使用Enumerable#lazy:
arr.lazy.select(&:odd?).take(3).force
# => [1, 3, 5]
force
用于强制惰性枚举器进行求值。或者,您可以使用first
,因为它非常渴望:
arr.lazy.select(&:odd?).first(3)
# => [1, 3, 5]
答案 1 :(得分:5)
代码和示例
arr.take_while.with_object([]) do |e,a|
a << e if e.odd?
a.size < 3
end
#=> [1, 3, 5]
<强>基准强>
require 'fruity'
def compare_em(arr, m)
compare(
lazy: -> { arr.lazy.select(&:odd?).take(m).force },
take_while: -> { arr.take_while.with_object([]) { |e,a|
a << e if e.odd?; a.size < m } }
)
end
n = 1e6
arr = (1..n).to_a.shuffle
获得前1000个元素:
compare_em(arr, 1e3)
# Running each test 8 times. Test will take about 1 second.
# take_while is faster than lazy by 2x ± 1.0
获取前10,000个奇数元素:
compare_em(arr, 1e4)
# Running each test once. Test will take about 1 second.
# take_while is faster than lazy by 2x ± 1.0
获得前100,000个元素:
compare_em(arr, 1e5)
# Running each test once. Test will take about 3 seconds.
# take_while is faster than lazy by 2x ± 0.1
我很惊讶lazy
做得很好,因为它在基准测试中往往要慢得多。