我注意到array.min
似乎很慢,所以我针对自己的天真实施做了这个测试:
require 'benchmark'
array = (1..100000).to_a.shuffle
Benchmark.bmbm(5) do |x|
x.report("lib:") { 99.times { min = array.min } }
x.report("own:") { 99.times { min = array[0]; array.each { |n| min = n if n < min } } }
end
结果:
Rehearsal -----------------------------------------
lib: 1.531000 0.000000 1.531000 ( 1.538159)
own: 1.094000 0.016000 1.110000 ( 1.102130)
-------------------------------- total: 2.641000sec
user system total real
lib: 1.500000 0.000000 1.500000 ( 1.515249)
own: 1.125000 0.000000 1.125000 ( 1.145894)
我很震惊。如何通过each
运行块的自己的实现击败内置?并且打败了这么多?
我有点错吗?或者这是不正常的?我很困惑。
我的Ruby版本,在Windows 8.1 Pro上运行:
C:\>ruby --version
ruby 2.2.3p173 (2015-08-18 revision 51636) [i386-mingw32]
答案 0 :(得分:3)
查看Enumerable#min的实施情况。它最终可能会使用each
循环遍历元素并获取min元素,但在此之前它会进行一些额外的检查以查看是否需要返回多个元素,或者是否需要通过一个元素来比较元素通过块。在你的情况下,元素将通过min_i函数进行比较,我怀疑速度差异来自哪里 - 该函数将比简单比较两个数字慢。
对阵列没有额外的优化,所有的枚举都以相同的方式遍历。
答案 1 :(得分:2)
如果你使用它会更快:
def my_min(ary)
the_min = ary[0]
i = 1
len = ary.length
while i < len
the_min = ary[i] if ary[i] < the_min
i += 1
end
the_min
end
注意强>
我知道这不是一个答案,但我认为值得分享并将此代码放入评论会非常难看。
答案 2 :(得分:1)
对于那些喜欢升级到较新版本软件的人
require 'benchmark'
array = (1..100000).to_a.shuffle
Benchmark.bmbm(5) do |x|
x.report("lib:") { 99.times { min = array.min } }
x.report("own:") { 99.times { min = array[0]; array.each { |n| min = n if n < min } } }
end
Rehearsal -----------------------------------------
lib: 0.021326 0.000017 0.021343 ( 0.021343)
own: 0.498233 0.001024 0.499257 ( 0.499746)
-------------------------------- total: 0.520600sec
user system total real
lib: 0.018126 0.000000 0.018126 ( 0.018139)
own: 0.492046 0.000000 0.492046 ( 0.492367)
RUBY_VERSION # => "2.7.1"
如果您想以真正高效的方式解决此问题:O(log(n))或O(n),请查看https://en.wikipedia.org/wiki/Selection_algorithm#Incremental_sorting_by_selection和https://en.wikipedia.org/wiki/Heap_(data_structure)