Ruby の Array#index は、要素とブロックを渡すの、どっちが速いの?

Array#index を使って、配列に含まれる要素の位置を取得したい。配列の要素が配列やハッシュで、一意に識別可能なIDが含まれる場合、探し方は、要素を直接渡すのと(==で比較する)、ブロックを渡す方法がある。

# ハッシュをそのまま渡す。
array.index hash

# ハッシュの値をブロックで比較する。
array.index { |hash2| hash[:id] == hash2[:id] }

どっちが速いのか気になったので、ベンチマークをとった。Ruby 1.9.3p283。

自分の予想は「配列の要素に含まれる要素数がある程度多くなると、ブロックの方が速くなる」。

実際には、要素の要素数と関係なくブロックを渡す方が速かった。

$ ruby array_index_bench.rb
                user   system    total       real
value value 0.140000 0.000000 0.140000 ( 0.144671)
value block 0.250000 0.000000 0.250000 ( 0.246818)
array value 1.660000 0.000000 1.660000 ( 1.659921)
array block 0.290000 0.000000 0.290000 ( 0.295605)
hash value  1.870000 0.000000 1.870000 ( 1.866465)
hash block  0.370000 0.000000 0.370000 ( 0.373319)

ただの数値の配列だとブロックを渡すよりも値を直接渡す方が速い。配列やハッシュではブロックを渡す方が速い。

まとめ

配列の要素が配列やハッシュで一意に識別できる値が含まれる場合は、

array.index hash

と書くより、

array.index { |hash2| hash[:id] == hash2[:id] }

と書いた方がよさそう。