Ruby - 通过嵌套属性选择属于两个数组的项目的最快方法

时间:2015-07-17 22:19:35

标签: ruby-on-rails ruby postgresql

我的Ruby查询非常慢。我正在寻找一种更快的方法来选择属于两个数组的项目

listA是具有属性name

的objectA列表

listB是具有属性name

的objectB列表

listA中的多个项目都可以包含namelistB,但name中的任何内容都不会listAname中还有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

3 个答案:

答案 0 :(得分:5)

您希望最大化查找速度。查找的最佳速度是使用Hashes的O(1)。我的方法比您的代码快1000倍,比id include?的循环快350倍

编辑2 This link详细解释了为什么哈希查找速度很快。

n=10000

编辑:更新基准。

  • 03/08/2015 - 添加了user12341234 set method

基准代码

names = {}
listB.each{|item| names[item.name] = true}
result = listA.select{|item| names[item.name]}

<强>基准

规格:

  • Intel Core i7 920 @ 2.67 GHz
  • 13 GB RAM
  • Windows 8 x64
  • Ruby 21 x64

结果:

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)