我有一个程序可以存储一个类的许多实例,比方说高达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是否存在(而不是对象本身!)
答案 0 :(得分:98)
哈希 更快查找:
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)
答案 1 :(得分:5)
Ruby在其标准库中有一个set类,您是否考虑过只保留一组(附加)ID?
http://stdlib.rubyonrails.org/libdoc/set/rdoc/index.html
引用文档:“这是Array的直观互操作设施和Hash快速查找的混合体。”
答案 2 :(得分:3)
使用唯一值时,您可以使用之前提到的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进行此测试。
答案 3 :(得分:2)
使用一套文件。它具有您想要的大多数属性(常量查找并且不允许重复)。 Smalltalkers会告诉你,使用已经拥有你想要的属性的集合是最重要的战斗。
按文档ID使用Hash of Documents,|| =用于条件插入(而不是has_key?)。
哈希设计用于恒定时间插入和查找。 Ruby的Set在内部使用Hash。
请注意您的Document对象需要实现#hash和#eql?正确地使它们像你希望的那样表现为哈希键或集合的成员,因为它们用于定义哈希相等。