Rubyの記事久々すぎて書き方忘れたw
環境
- ruby 2.7
やりたいこと
タイトル通りだが、例えば a〜zの配列でaとkにマッチする要素を取得するときはselectでいける
array = ("a".."z").to_a array.select{|item| item == "a" || item == "k" } # => ["a", "k"]
が、今回は要素そのものではなく要素が格納されている配列のインデックスが知りたい。
コード
意外にもRubyにネイティブなメソッドは用意されてないっぽい。そこで array.each_index.select
をつかうことにした
array.each_index.select{|i| array[i] == "a" || array[i] == "k" } # => [0, 10]
each_indexでindexのEnumeratorオブジェクトを生成し、selectで評価していく方法。これが一番しっくり来た
他にも
色々あるっぽい。そこでベンチマークをとってみた。
require 'benchmark' arr = 10000000.times.map{rand(1000)}; Benchmark.bm(7) do |x| x.report("arr.each_with_index.map:") { arr.each_with_index.map { |a, i| a == 50 ? i : nil }.compact } x.report("arr.size-1 .select:") { (0..arr.size-1).select { |i| arr[i] == 50 } } x.report("arr.map.with_index:") { arr.map.with_index {|a, i| a == 50 ? i : nil}.compact } x.report("arr.each_index.select:") { arr.each_index.select{|i| arr[i] == 50} } x.report("arr.size.times.select:") { arr.size.times.select {|i| arr[i] == 50} } end
結果
user system total real arr.each_with_index.map: 1.006136 0.055187 1.061323 ( 1.062394) arr.size-1 .select: 0.754916 0.000831 0.755747 ( 0.757302) arr.map.with_index: 0.879967 0.055472 0.935439 ( 0.936816) arr.each_index.select: 0.734339 0.000641 0.734980 ( 0.735821) arr.size.times.select: 0.732360 0.000913 0.733273 ( 0.734476)
速度でなら arr.size.times.select
が最強か。上で紹介した arr.each_index.select
も悪くなさそう。