Arrays 如何从数组中获取第一个匹配项
给定一个数组:Arrays 如何从数组中获取第一个匹配项,arrays,ruby,Arrays,Ruby,给定一个数组:[1,2,3,5,8.13] 我可以选择大于3的所有项目: [1, 2, 3, 5, 8. 13].select { |num| num > 3 } (我知道速记select(&:>)语法,这不是重点) 我现在可以很容易地返回第一个 [1, 2, 3, 5, 8. 13].select { |num| num > 3 }.first 但是,当实际的比较变得沉重时,这不是很有效。我正在尝试优化一个案例,在这个案例中,我们有300多个项目的数组,select将在几乎所有
[1,2,3,5,8.13]
我可以选择大于3的所有项目:
[1, 2, 3, 5, 8. 13].select { |num| num > 3 }
(我知道速记select(&:>)
语法,这不是重点)
我现在可以很容易地返回第一个
[1, 2, 3, 5, 8. 13].select { |num| num > 3 }.first
但是,当实际的比较变得沉重时,这不是很有效。我正在尝试优化一个案例,在这个案例中,我们有300多个项目的数组,select将在几乎所有案例中返回第一个项目(并且数组已经排序)。此外,我们进行比较的代码相当繁重(例如,需要往返到db)
有没有ruby速记法可以先取第一个,然后停下来?类似于:
[1, 2, 3, 5, 8. 13].each do |num|
return num if num > 3
end
只需使用:
您可以使用:
对于您的问题,这显然是最好的,但是假设集合很大,并且您希望第一个n>1
元素大于3
?使用lazy
,您可以编写:
(0..100_000_000_000).lazy.select { |num| num > 3 }.first(2)
# => [4, 5]
它会在眨眼之间执行。使用二进制搜索,它会在
O(logn)
下面是一个细分:
最慢的:
2.1.2 :011 > [1, 2, 3, 5, 8, 13].sort.bsearch { |num| num > 3 }
=> 5
慢:
2.1.2 :010 > [1, 2, 3, 5, 8, 13].find { |num| num > 3 }
=> 5
最快:
2.1.2 :012 > [1, 2, 3, 5, 8, 13].bsearch { |num| num > 3 }
=> 5
2.1.2 :013 >
下面是我刚刚编写的比较所有方法的小脚本:
$ cat ./benchmark_find_bsrch.rb
#!/usr/bin/env ruby
require 'benchmark/ips'
DATA = Array(0..10)
def find
DATA.find { |num| num > 3 }
end
def sort_bsearch
[10,9,8,4,5,6,1,2,3,7].sort.bsearch { |num| num > 3 }
end
def bsearch
DATA.bsearch { |num| num > 3 }
end
def select
DATA.select { |num| num > 3 }
end
def lazy_select
DATA.lazy.select { |num| num > 3 }.first
end
Benchmark.ips do |bm|
bm.report('find'){ find }
bm.report('sort_bsearch'){ sort_bsearch }
bm.report('bsearch'){ bsearch }
bm.report('select'){select }
bm.report('lazy_select') {lazy_select}
bm.compare!
end
其输出如下:
util-scripts$ ./benchmark_find_bsrch.rb
Calculating -------------------------------------
find 63.607k i/100ms
sort_bsearch 52.039k i/100ms
bsearch 95.260k i/100ms
select 57.218k i/100ms
lazy_select 11.850k i/100ms
-------------------------------------------------
find 1.130M (± 5.0%) i/s - 5.661M
sort_bsearch 809.723k (± 6.5%) i/s - 4.059M
bsearch 2.099M (± 6.1%) i/s - 10.479M
select 929.578k (± 2.6%) i/s - 4.692M
lazy_select 140.782k (± 8.1%) i/s - 711.000k
Comparison:
bsearch: 2098632.5 i/s
find: 1129912.5 i/s - 1.86x slower
select: 929578.3 i/s - 2.26x slower
sort_bsearch: 809722.5 i/s - 2.59x slower
lazy_select: 140782.2 i/s - 14.91x slower
我希望你觉得这有用:)谢谢。我在仔细阅读数组的API文档,但从未看过可枚举的。唉,对整个数组进行排序以找到大于
3
的第一个元素真是太疯狂了。假设数组很大,第一个3
接近疯狂的开始?你不需要一个基准来断定排序是荒谬的。伊加德!有一个上升的投票.find
是O(n)
,.sort
是O(n log(n))
。奇怪的是,使用排序
的解决方案比在足够大的数组
上使用查找
的解决方案要快。谢谢@Cary Swoveland,@Akavall的输入,我把这个颠倒过来了。。。然而,对于上面给定的场景,bsearch仍然是最重要的。因此,数组被排序了。我尝试了DATA=array.new(1e6){rand 1e6}
的基准测试。结果是find
最快,bsearch
2.20倍慢,lazy\u-select
12.66倍慢,select
,126779倍慢,sort\u-bsearch
,330906倍慢。这正是我所期望的。请注意,我没有建议对这个问题使用lazy
。我的论点是,如果您想要获得多个满足块中条件的值,则可能需要使用lazy
。我误解了b搜索
,认为它也是先排序的。注意sort\u bsearch
需要在脚本中修复(DATA.sort\u bsearch…
)。@Akavail,您不能从只考虑包含11个元素的数组的基准中得出结论。所有方法都有设置时间,如果集合较小,则可能会淹没总数。由于集合较大,因此在需要优化时,此方法效果良好。但是我的问题需要优化,因为比较很难:更像是[1,2,3,5,8,13]。选择{num{bcrypt(num)==bcrypt(3)}。首先
懒惰不会有多大帮助。正如我所说,使用查找
解决问题,但是懒惰
可能对变体有用。至于select
是否应该与lazy
一起使用,这主要取决于数组的大小select
将对数组中的每个元素执行块计算(在执行first
之前),而lazy.select
将执行相同的计算,但在选择满足条件的第一个元素后将停止。我想你是在反对使用select
,lazy
。我不会不同意。
$ cat ./benchmark_find_bsrch.rb
#!/usr/bin/env ruby
require 'benchmark/ips'
DATA = Array(0..10)
def find
DATA.find { |num| num > 3 }
end
def sort_bsearch
[10,9,8,4,5,6,1,2,3,7].sort.bsearch { |num| num > 3 }
end
def bsearch
DATA.bsearch { |num| num > 3 }
end
def select
DATA.select { |num| num > 3 }
end
def lazy_select
DATA.lazy.select { |num| num > 3 }.first
end
Benchmark.ips do |bm|
bm.report('find'){ find }
bm.report('sort_bsearch'){ sort_bsearch }
bm.report('bsearch'){ bsearch }
bm.report('select'){select }
bm.report('lazy_select') {lazy_select}
bm.compare!
end
util-scripts$ ./benchmark_find_bsrch.rb
Calculating -------------------------------------
find 63.607k i/100ms
sort_bsearch 52.039k i/100ms
bsearch 95.260k i/100ms
select 57.218k i/100ms
lazy_select 11.850k i/100ms
-------------------------------------------------
find 1.130M (± 5.0%) i/s - 5.661M
sort_bsearch 809.723k (± 6.5%) i/s - 4.059M
bsearch 2.099M (± 6.1%) i/s - 10.479M
select 929.578k (± 2.6%) i/s - 4.692M
lazy_select 140.782k (± 8.1%) i/s - 711.000k
Comparison:
bsearch: 2098632.5 i/s
find: 1129912.5 i/s - 1.86x slower
select: 929578.3 i/s - 2.26x slower
sort_bsearch: 809722.5 i/s - 2.59x slower
lazy_select: 140782.2 i/s - 14.91x slower