1つのクラスの多くのインスタンスを格納するプログラムがあります。たとえば、最大で10.000以上です。クラスインスタンスには、時々必要となるいくつかのプロパティがありますが、最も重要なものはIDです。
class Document
attr_accessor :id
def ==(document)
document.id == self.id
end
end
さて、これらの何千ものオブジェクトを保存する最も速い方法は何ですか?
私はそれらすべてを一連のドキュメントに入れていました:
documents = Array.new
documents << Document.new
# etc
今、代替策はそれらをハッシュに格納することです:
documents = Hash.new
doc = Document.new
documents[doc.id] = doc
# etc
私のアプリケーションでは、ほとんどの場合、ドキュメントが存在するかどうかを確認する必要があります。ハッシュのhas_key?
関数は、配列の線形検索およびDocument
オブジェクトの比較よりも大幅に高速ですか?両方がO(n)内にあるか、has_key?
であってもO(1)です。違いがわかりますか?
また、ドキュメントが既に存在する場合、ドキュメントを追加する必要がある場合があります。配列を使用する場合は、以前にinclude?
で確認する必要があります。ハッシュを使用する場合は、もう一度has_key?
を使用します。上記と同じ質問です。
あなたの考えは何ですか? 90%の時間でIDが存在するかどうか(オブジェクト自体ではない!)
ハッシュはmuchルックアップの方が高速です:
require 'benchmark'
Document = Struct.new(:id,:a,:b,:c)
documents_a = []
documents_h = {}
1.upto(10_000) do |n|
d = Document.new(n)
documents_a << d
documents_h[d.id] = d
end
searchlist = Array.new(1000){ Rand(10_000)+1 }
Benchmark.bm(10) do |x|
x.report('array'){searchlist.each{|el| documents_a.any?{|d| d.id == el}} }
x.report('hash'){searchlist.each{|el| documents_h.has_key?(el)} }
end
# user system total real
#array 2.240000 0.020000 2.260000 ( 2.370452)
#hash 0.000000 0.000000 0.000000 ( 0.000695)
Rubyの標準ライブラリにはセットクラスがあります。IDの(追加の)セットのみを保持することを検討していますか?
http://stdlib.rubyonrails.org/libdoc/set/rdoc/index.html
ドキュメントを引用すると、「これはアレイの直感的な相互運用機能とハッシュの高速ルックアップのハイブリッドです」。
一意の値を使用する場合は、前述の Ruby Set を使用できます。以下はベンチマーク結果です。ただし、ハッシュよりも少し遅いです。
user system total real
array 0.460000 0.000000 0.460000 ( 0.460666)
hash 0.000000 0.000000 0.000000 ( 0.000219)
set 0.000000 0.000000 0.000000 ( 0.000273)
ここにある@steenslagのコードに単に追加しました https://Gist.github.com/rsiddle/a87df54191b6b9dfe7c9 。
このテストではRuby 2.1.1p76を使用しました。
ドキュメントのセットを使用します。これには、必要なほとんどのプロパティがあります(一定時間のルックアップで、重複は許可されていません)。 Smalltalkerは、必要なプロパティが既に設定されているコレクションを使用することが、ほとんどの場合の戦いだと言っています。
条件付き挿入には(has_key?ではなく)、|| =を使用して、ドキュメントIDでドキュメントのハッシュを使用します。
ハッシュは、一定時間の挿入と検索のために設計されています。 Rubyのセットは内部でハッシュを使用します。
Documentオブジェクトは#hashと#eqlを実装する必要があることに注意してください。それらがハッシュの等価性を定義するために使用されるため、それらがハッシュキーまたはセットのメンバーとして期待どおりに動作するために適切に。