結論:ruby 2.4 は素晴らしい
http://qiita.com/Nabetani/items/b48f5cb6361496ca7712
で議論になった、最大値の求め方。
lazy_map_max
size.times.lazy.map{ |x| f(x) }.max
inject_cond
size.times.inject(0){ |acc,x| t=f(x);acc=t<acc ? acc : t }
inject_max
size.times.inject(0){ |acc,x| [acc,f(x)].max }
map_max
size.times.map{ |x| f(x) }.max
と、いろいろ方法がある。で。実行時間を比較する。
対象は ruby 2.3.3p222 と、ruby 2.4.0p0 。
実行時間なので、短いほど良い。
速度重視で選ぶなら、ruby2.3 だと、inject_cond 一択。ruby2.4 だと、lazy_map_max 以外ならどれでも同じ。という事になった。
https://docs.ruby-lang.org/ja/latest/doc/news=2f2_4_0.html
の
いくつかの条件で [x,y].max と [x,y].min が一時的な配列を生成しないよう最適化されました。
の効果によって、 ruby2.4 では inject_max が速くなっていて、inject_cond に追いついた感じ。
map_max も相当速くなっていて、こちらも inject_cond に追いついているけど、これはなんでなんだろう。
lazy を使ったコードはやっぱり遅かった。
実験に使ったのはこんなコード:
bench.rb
#encode:utf-8
(p RUBY_DESCRIPTION) rescue p "1.8.x or former"
require "benchmark"
def f(x)
(x/3) & (x/7)
end
def map_max(size)
size.times.map{ |x| f(x) }.max
end
def lazy_map_max(size)
size.times.lazy.map{ |x| f(x) }.max
end
def inject_max(size)
size.times.inject(0){ |acc,x| [acc,f(x)].max }
end
def inject_cond(size)
size.times.inject(0){ |acc,x| t=f(x);acc=t<acc ? acc : t }
end
def run_bench( n, size )
puts "n, size = #{n}, #{size}"
m=[ :map_max, :inject_max, :inject_cond, :lazy_map_max ]
len = m.map(&:to_s).map(&:size).max
Benchmark.bmbm(len) do |x|
m.each do |s|
x.report(s.to_s){
n.times do
self.send(s, size)
end
}
end
end
end
run_bench( 100, 100000 )