巨大な配列と、そこからの値があります。配列の値のインデックスを取得したい。他の方法がありますが、Array#index
を呼び出して取得しますか?問題は、本当に巨大な配列を保持し、Array#index
を膨大な回数呼び出す必要があるためです。
数回の試行の後、値自体の代わりに(value, index)
フィールドを持つ構造体を格納することでcaching要素内のインデックスを作成することで、パフォーマンスが大幅に向上します(20倍の勝利)。
それでも、キャッシュせずにen要素のインデックスを検索するより便利な方法があるのだろうか(または、パフォーマンスを向上させる優れたキャッシュ技術があるのか)。
配列をハッシュに変換します。次に、キーを探します。
array = ['a', 'b', 'c']
hash = Hash[array.map.with_index.to_a] # => {"a"=>0, "b"=>1, "c"=>2}
hash['b'] # => 1
なぜindexまたはrindexを使用しないのですか?
array = %w( a b c d e)
# get FIRST index of element searched
puts array.index('a')
# get LAST index of element searched
puts array.rindex('a')
インデックス: http://www.Ruby-doc.org/core-1.9.3/Array.html#method-i-index
rindex: http://www.Ruby-doc.org/core-1.9.3/Array.html#method-i-rindex
他の回答では、エントリが配列に複数回リストされる可能性を考慮していません。これは、各キーが配列内の一意のオブジェクトであり、各値がオブジェクトの存在場所に対応するインデックスの配列であるハッシュを返します。
a = [1, 2, 3, 1, 2, 3, 4]
=> [1, 2, 3, 1, 2, 3, 4]
indices = a.each_with_index.inject(Hash.new { Array.new }) do |hash, (obj, i)|
hash[obj] += [i]
hash
end
=> { 1 => [0, 3], 2 => [1, 4], 3 => [2, 5], 4 => [6] }
これにより、重複したエントリをすばやく検索できます。
indices.select { |k, v| v.size > 1 }
=> { 1 => [0, 3], 2 => [1, 4], 3 => [2, 5] }
ハッシュを使用しない正当な理由はありますか?ルックアップは、配列のO(1)
対O(n)
です。
ソート済み配列の場合、バイナリ検索アルゴリズム(O(log n)
)を使用できます。たとえば、次の機能を使用してArrayクラスを拡張します。
class Array
def b_search(e, l = 0, u = length - 1)
return if lower_index > upper_index
midpoint_index = (lower_index + upper_index) / 2
return midpoint_index if self[midpoint_index] == value
if value < self[midpoint_index]
b_search(value, lower_index, upper_index - 1)
else
b_search(value, lower_index + 1, upper_index)
end
end
end
@sawaの回答とそこにリストされているコメントを組み合わせて、配列クラスに「クイック」インデックスとrindexを実装できます。
class Array
def quick_index el
hash = Hash[self.map.with_index.to_a]
hash[el]
end
def quick_rindex el
hash = Hash[self.reverse.map.with_index.to_a]
array.length - 1 - hash[el]
end
end
配列に自然順序がある場合は、バイナリ検索を使用します。
バイナリ検索を使用します。
バイナリ検索にはO(log n)
アクセス時間があります。
バイナリ検索の使用方法の手順は次のとおりです。
bsearch
を使用して、要素またはインデックスを検索しますコード例
# assume array is sorted by name!
array.bsearch { |each| "Jamie" <=> each.name } # returns element
(0..array.size).bsearch { |n| "Jamie" <=> array[n].name } # returns index
それでも、キャッシュせずにen要素のインデックスを検索するより便利な方法があるのだろうか(または、パフォーマンスを向上させる優れたキャッシュ技術があるのか)。
バイナリ検索を使用できます(配列が順序付けられている場合and配列に格納する値は何らかの方法で比較可能です)。それが機能するためには、現在の要素の「左」または「右」のどちらに見えるべきかをバイナリ検索に伝えることができる必要があります。しかし、挿入時にindex
を保存し、同じ配列から要素を取得している場合はそれを使用しても問題はないと思います。