我想选择匹配某个条件的数组的前10个元素,而不必遍历整个数组。我知道find
让我成为第一个元素。例如,下面的代码给出了第一个大于100的素数:
require 'prime'
puts Prime.find {|p| p > 100 } #=> 101
有没有办法让前10个大于100的素数?
答案 0 :(得分:7)
在Ruby 2.0+中你可以写:
require 'prime'
Prime.lazy.select{|p| p > 100 }.take(10).to_a #=> [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]
答案 1 :(得分:3)
您可以手动执行此操作,例如
def check_for_primes(start_number, desired_size)
result = []
suspect = start_number
while result.size < desired_size do
result << suspect if suspect.prime?
suspect += 1
end
result
end
check_for_primes 100, 10
#=> [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]
使用简单的ruby迭代。
适用于所有ruby版本。
而不是(无可争议的非ruby之类)while循环,我们可以添加 @ cary-swoveland 的变体,其中有相当一些红宝石的好处。
check_enum_text(start_number, desired_size)
(start_number..1.0/0).each_with_object([]) do |n,arr|
if n.prime?
arr << n;
return arr if arr.size == desired_size
end
end
end
<强> *********** UPDATE *********** 强>
和一些性能基准
require 'benchmark'
a_gazillion = 10000000000
Benchmark.bm do |x|
x.report("lazy_select") { Prime.lazy.select{|p| p > (a_gazillion / 1000) }.take(10).to_a }
x.report("prime_each") { arr = []; Prime.each{|p| arr << p if p > a_gazillion / 1000; break if arr.count == 10 } }
x.report("while_loop") { check_for_primes a_gazillion, 10 }
x.report("enum_text") { check_enum_text a_gazillion, 10 }
end
user system total real
lazy_select 75.360000 0.240000 75.600000 (84.259781)
prime_each 6.100000 0.040000 6.140000 ( 6.730646)
while_loop 0.620000 0.000000 0.620000 ( 0.655504)
enum_text 0.610000 0.000000 0.610000 ( 0.770726)
从我们看到的两个最新的解决方案是那些表现最好的解决方案。从一些额外的基准测试(通过调整desired_size)我无法得出哪一个更好
def bench(start, length)
Benchmark.bm do |x|
x.report("enum_text") { check_enum_text start, length }
x.report("while_loop") { check_for_primes start, length}
end
end
bench a_gazillion, 100
user system total real
enum_text 6.350000 0.000000 6.350000 ( 6.974557)
while_loop 6.530000 0.000000 6.530000 ( 7.330884)
bench a_gazillion, 500
user system total real
enum_text 31.880000 0.110000 31.990000 ( 36.723209)
while_loop 32.850000 0.060000 32.910000 ( 38.569744)
性能类似(实际上 @ cary-swoveland 的解决方案表现稍好一些),所以我必须使用该解决方案,因为它更像红宝石!
答案 2 :(得分:2)
arr = []
Prime.each{|p| arr << p if p > 100; break if arr.count == 10 }
puts arr
答案 3 :(得分:2)
一些答案的缺点是它们多次枚举低于阈值的素数。这是避免这种情况的一种方法:
require 'prime'
def check_for_primes(start_number, desired_size)
return [] if desired_size.zero?
enum = Prime.each
[enum.find { |n| n >= start_number }] + enum.first(desired_size-1)
end
check_for_primes(100, 10)
#=> [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]
或者,可以这样写:
def check_for_primes(start_number, desired_size)
return [] if desired_size.zero?
enum = Prime.each
(0..1.0/0).each_with_object([]) do |_,arr|
n = enum.next
if n >= start_number
arr << n
return arr if arr.size == desired_size
end
end
end
答案 4 :(得分:1)
一种简单的迭代方式:
require 'prime'
initial = 100
list = []
10.times do |x|
initial = Prime.find {|p| p > initial}
list << initial
end
puts list
答案 5 :(得分:1)
您可以使用Prime.each(n)
设置上限:
Prime.each(1000).drop_while { |p| p <= 100 }.take(10)
# => [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]
或者,您可以计算许多素数 100以下,然后取+ + 10:
Prime.take(Prime.take_while { |p| p <= 100 }.count + 10)[-10..-1]
# => [101, 103, 107, 109, 113, 127, 131, 137, 139, 149]