テストを書いてる時にふと気になったので検証してみた.
結果から言うと
Ruby2.5以降とRailsではコレが鉄板
早くてシンプル!
months.slice(:jan, :jun, :jul)
# => {:jan=>"1月", :jun=>"6月", :jul=>"7月"}
Ruby 2.4以前でRailsを使わない場合は
シンプルに書くなら
months.select {|k,_| [:jan, :jun, :jul].include?(k) }
# => {:jan=>"1月", :jun=>"6月", :jul=>"7月"}
早いけど、少し長い
keys = [:jan, :jun, :jul]
keys.each_with_object({}){|k, hash| hash[k] = months[k] if months.key?(k) }
# => {:jan=>"1月", :jun=>"6月", :jul=>"7月"}
検証
思いつく限りと、コメントで頂いた方法で検証してみた.
リテラルで表記してるから、インタプリタがうまいことやってて同じくらいの結果を期待してたけど、結構違うもんだな。
benchmark
ruby 2.2.0
user system total real
Enumerable#each_with_object 1.010000 0.000000 1.010000 ( 1.020658)
Hash#select: out of loop 2.010000 0.000000 2.010000 ( 2.027411)
Hash#select: in the loop 2.560000 0.010000 2.570000 ( 2.583571)
Hash#slice: active_support 1.570000 0.010000 1.580000 ( 1.590525)
require 'benchmark'
require 'active_support'
puts "ruby #{RUBY_VERSION}"
n = 1000000
months = {
jan: "1月", feb: "2月", mar: "3月", apr: "4月", may: "5月", jun: "6月",
jul: "7月", aug: "8月", sep: "9月", oct: "10月", nov: "11月", dec: "12月"
}
Benchmark.bm(30) do |x|
x.report("Enumerable#each_with_object") do
keys = [:jan, :jun, :jul]
n.times do
keys.each_with_object({}){|k, hash| hash[k] = months[k] if months.key?(k) }
end
end
x.report("Hash#select: out of loop") do
keys = [:jan, :jun, :jul]
n.times do
months.select {|k,_| keys.include?(k) }
end
end
x.report("Hash#select: in the loop") do
n.times do
months.select {|k,_| [:jan, :jun, :jul].include?(k) }
end
end
x.report("Hash#slice: active_support") do
n.times do
months.slice(:jan, :jun, :jul)
end
end
end