红宝石:比较散列值的两个数组(Ruby: Comparing two Arrays of Hashe

2019-08-18 16:49发布

我的确是新手,红宝石(和使用1.9.1),所以任何帮助表示赞赏。 一切,我已经了解了红宝石已经从使用谷歌。 我想比较散列值的两个阵列,并且由于尺寸,它采取的方式长,与运行内存调情。 任何帮助,将不胜感激。

我有一类(ParseCSV)用多种方法(初始化,打开,比较,带材,输出)。 我的方式是正确的,现在的工作是如下(这不通过我写的测试,只是用更小的数据集):


file1 = ParseCSV.new(“some_file”)
file2 = ParseCSV.new(“some_other_file”)

file1.open #this reads the file contents into an Array of Hash’s through the CSV library 
file1.strip #This is just removing extra hash’s from each array index.  So normally there are fifty hash’s in each array index, this is just done to help reduce memory consumption.  

file2.open 
file2.compare(“file1.storage”) #@storage is The array of hash’s from the open method

file2.output

现在我正在挣扎的比较方法。 在较小的数据的工作集这不是什么大不了的事可言,工作速度不够快。 然而,在这种情况下,我比较约40万条记录(所有读入散列的数组)对一个有45万条记录。 我试图加快这。 还我不能运行在文件2的条法。 下面是我怎么做,现在:


def compare(x)
    #obviously just a verbose message
    puts "Comparing and leaving behind non matching entries"

    x.each do |row|
        #@storage is the array of hashes
        @storage.each_index do |y|       
            if row[@opts[:field]] == @storage[y][@opts[:field]]
               @storage.delete_at(y)
            end
       end
    end
end

希望这是有道理的。 我知道这将是仅仅因为遍历40万行,每行44万次一个缓慢的过程。 但是,你有没有对如何加快进行,并有可能降低内存消耗任何其他的想法?

Answer 1:

哎呀,那将是为O(n)的平方运行。 讨厌。

更好的选择是使用内置的集合类。

代码看起来是这样的:

require 'set'

file1_content = load_file_content_into_array_here("some_file")
file2_content = load_file_content_into_array_here("some_other_file")

file1_set = Set[file1_content]

unique_elements = file1_set - file2_content

这假定文件本身具有独特的内容。 如果在一般的情况下工作,但可能有毛病取决于你的数据样子,你如何分析它,但只要该线可以与之比较==它应该帮助你。

使用一组会比做一个嵌套的循环来遍历文件内容更快。

(是的,其实我已经做到了这一点,以处理与约2个百万行的文件,所以它应该能够处理您的案件 - 最终如果你正在做大量的数据改写(munging),红宝石可能不是工具的最佳选择,虽然)



Answer 2:

这里的比较做这件事的两种方法的脚本:你原来的比较()和new_compare()。 该new_compare使用更多的内置的可枚举的方法。 由于它们是用C语言实现,他们会更快。

我创建了一个名为Test :: SIZE尝试用不同的散列大小的基准不变。 结果在底部。 所不同的是巨大的。

require 'benchmark'

class Test
  SIZE = 20000
  attr_accessor :storage
  def initialize
    file1 = []
    SIZE.times { |x| file1 << { :field => x, :foo => x } }
    @storage = file1
    @opts = {}
    @opts[:field] = :field
  end

  def compare(x)
    x.each do |row|
      @storage.each_index do |y|
        if row[@opts[:field]] == @storage[y][@opts[:field]]
          @storage.delete_at(y)
        end
      end
    end
  end

  def new_compare(other)
    other_keys = other.map { |x| x[@opts[:field]] }
    @storage.reject! { |s| other_keys.include? s[@opts[:field]] }
  end

end

storage2 = []
# We'll make 10 of them match
10.times { |x| storage2 << { :field => x, :foo => x } }
# And the rest wont
(Test::SIZE-10).times { |x| storage2 << { :field => x+100000000, :foo => x} }

Benchmark.bm do |b|
  b.report("original compare") do
    t1 = Test.new
    t1.compare(storage2)
  end
end

Benchmark.bm do |b|
  b.report("new compare") do
    t1 = Test.new
    t1.new_compare(storage2)
  end
end

结果:

Test::SIZE = 500
      user     system      total        real
original compare  0.280000   0.000000   0.280000 (  0.285366)
      user     system      total        real
new compare  0.020000   0.000000   0.020000 (  0.020458)

Test::SIZE = 1000
     user     system      total        real
original compare 28.140000   0.110000  28.250000 ( 28.618907)
      user     system      total        real
new compare  1.930000   0.010000   1.940000 (  1.956868)

Test::SIZE = 5000
ruby test.rb
      user     system      total        real
original compare113.100000   0.440000 113.540000 (115.041267)
      user     system      total        real
new compare  7.680000   0.020000   7.700000 (  7.739120)

Test::SIZE = 10000
      user     system      total        real
original compare453.320000   1.760000 455.080000 (460.549246)
      user     system      total        real
new compare 30.840000   0.110000  30.950000 ( 31.226218)


文章来源: Ruby: Comparing two Arrays of Hashes