rubyのselectやmapなどの計算量について
rubyで配列やHashなどのselectやmapなどを繰り返し呼んだ時ループは何回行われるのでしょうか?
例えば下記のコードでは
(1..100)
.select{|val| val % 2 == 0}
.map{|val| val.to_s}
.join " "
行われるループは3回、あるいは1回ループで3つの処理をするのでしょうか?
言語によっては遅延評価をしてループの回数を減らしてくれることもあるのでベンチマークをとって見たのですが、非常に混乱する結果でした。
試したのは下記のベンチです。比較のためeach_with_objectを使った処理も入れて見ました。
Benchmark.ips do |x|
x.report("repeat map") do
(1..10000)
.map{|val| val.to_s}
.map{|val| val.to_i}
.map{|val| val.to_s}
.map{|val| val.to_i}
end
x.report("each_with_object") do
(1..10000).each_with_object([]) do |val, res|
val = val.to_s
val = val.to_i
val = val.to_s
val = val.to_i
end
end
x.report("repeat each") do
range = (1..10000)
range.each do |val|
val = val.to_s
end
range.each do |val|
val = val.to_i
end
range.each do |val|
val = val.to_s
end
range.each do |val|
val = val.to_i
end
end
x.compare!
end
結果はこんな感じです(数が多いほど早いです)。
repeat map 140.435 (± 8.5%) i/s - 700.000 in 5.023912s
each_with_object 176.636 (± 5.1%) i/s - 884.000 in 5.017814s
repeat each 186.010 (± 5.4%) i/s - 936.000 in 5.048520s
repeat map
が繰り返しループされるのかわからないですが、repeat each
がeach_with_object
とほぼ変わらないのが解せませんでした。多分、私のテストしたコードになにか問題があるのだと思いますが・・・
配列やHashに対して気軽に、繰り返しselectやreject、mapなどを呼んでも良いのか気になったので投稿しました。
よろしくお願いします。