我的Ruby查询非常慢。我正在寻找一种更快的方法来选择属于两个数组的项目
listA
是具有属性name
listB
是具有属性name
listA
中的多个项目都可以包含name
个listB
,但name
中的任何内容都不会listA
。 name
中还有listB
s不在listA
中的项目。我想要一个函数(循环)来返回name
listB
所在的z = 0
new = []
while z < listB.length
hold = listA.select{|obj| obj.name == listB[z].name}
new += hold
z += 1
end
中的所有项目。
这是我目前的解决方案,但速度太慢了。我怎样才能让它更快?
currentStatus
答案 0 :(得分:5)
您希望最大化查找速度。查找的最佳速度是使用Hashes的O(1)。我的方法比您的代码快1000倍,比id
include?
的循环快350倍
编辑2 :This link详细解释了为什么哈希查找速度很快。
n=10000
编辑:更新基准。
基准代码
names = {}
listB.each{|item| names[item.name] = true}
result = listA.select{|item| names[item.name]}
<强>基准强>
规格:
结果:
class MyObject
def initialize(name)
@name = name
end
def name
@name
end
end
n=10000
k=n/10
listA = (1..n).map{ MyObject.new(('a'..'z').to_a.shuffle[0,8].join)}
listB = listA.sample(k)
listB += (1..(n-k)).map{ MyObject.new(('a'..'z').to_a.shuffle[0,8].join)}
require 'benchmark'
require 'set'
Benchmark.bm do |x|
x.report("Hash") do
names = {}
listB.each{|item| names[item.name] = true}
result = listA.select{|item| names[item.name]}
end
x.report("OP's code") do
z = 0
new = []
while z < listB.length
hold = listA.select{|obj| obj.name == listB[z].name}
new += hold
z += 1
end
end
x.report("Include") do
names = listB.map(&:name)
listA.select{|obj| names.include?(obj.name) }
end
x.report("Set") do
names = listB.map(&:name).to_set
listA.select{|item| names.include?(item.name)}
end
end
答案 1 :(得分:2)
类似的东西:
names = listB.map(&:name)
listA.select {|obj| names.inlude? obj.name }
答案 2 :(得分:1)
表达无序,非重复数据的自然方式是使用集合。尝试:
require 'set'
names = listB.map(&:name).to_set
listA.select{|item| names.include?(item.name)}
使用@ Cyrill_DD的基准测试,这与哈希实现相当:
user system total real
Set 0.010000 0.000000 0.010000 ( 0.012556)
Hash 0.010000 0.000000 0.010000 ( 0.011330)