Ruby - 从修改后的值重构哈希

时间:2015-04-12 22:34:47

标签: ruby

我正在编写一个程序,它将扫描目录,获取文件中行的校验和,并将其与某个数据库进行比较,返回匹配的条目。

我的数据库是一个json文件,包含文件名和行的校验和,它看起来像这样:

"HASHES": {
   "file_name": {
     "1": "checksum",
     "2": "checksum"
   },
   "file_name": {
     "1": "checksum",
     "2": "checksum
   },
   etc..
}
然后我扫描目录并构造一个类似的哈希(即file_name,行号,校验和的哈希)。这段代码有效。

我遇到的问题是从结果重建类似的哈希

这是我的代码:

def compare(dir_hash, database_hash)
  temp_hash     = database_hash.dup

  # retrieve the checksums from the dir_hash.
  dir_values    = dir_hash["HASHES"].sort_by(&:first).map { |x| x.last.values }

  # retrieve the checksums from database_hash
  db_values     = database_hash["HASHES"].sort_by(&:first).map { |x| x.last.values }

  # perform a set intersection to get the common values
  unique_values = dir_values.zip(db_values).map { |x| x.reduce(:&) }

  # code to reconstruct hash, based on new values
  new_hash      = temp_hash["HASHES"]

end

我似乎无法弄清楚如何使用修改后的值重建哈希。

帮助表示赞赏。

注意

sort_by(&:first)的目的是确保当我们执行集合交集时,我们在相同的值上执行它,换句话说,我从文件x获取集合的交集数据库中的目录和相同的文件x(由于Ruby不保留键的顺序)

由于sort_by将返回一个数组,第一个元素将是file_name,第二个元素将是行号的哈希值,校验和

2 个答案:

答案 0 :(得分:1)

另一种方法可以做到这一点:

intersect_ary = database_hash["HASHES"].keys & dir_hash["HASHES"].keys
new_hash = dir_hash
intersect_ary.each do |file|
  new_hash["HASHES"][file].select! {|key| new_hash["HASHES"][file][key] == database_hash["HASHES"][file][key]}
end

(假设你必须创建一个新的哈希而不是仅仅改变dir_hash

答案 1 :(得分:0)

我不太确定你的问题应该是什么样的正确输出,但是我正在开发一个旨在让它更容易使用嵌套集合的库,所以我想我会给它一个刺。这是你的想法吗?

注意:此解决方案依赖于https://github.com/dgopstein/deep_enumerable

中的代码
require './deep_enumerable/lib/deep_enumerable.rb'

dir_hash = {
  "HASHES": {
     "file1": {
       "1": "1",
       "2": "2"
     },
     "file2": {
       "1": "3",
       "2": "4"
     }
  }
}

database_hash = {
  "HASHES": {
     "file1": {
       "1": "1",
       "2": "3"
     },
     "file2": {
       "1": "2",
       "2": "4"
     }
  }
}

p dir_hash.deep_intersect(database_hash)
=> {:HASHES=>{:file1=>{:"1"=>"1"}, :file2=>{:"2"=>"4"}}}

或者没有库(在这个例子之外未经测试):

def deep_intersect(this, other, &block)
  empty = this.select{false}

  (this.keys + other.keys).each do |key|
    s_val = (this[key] rescue nil)
    o_val = (other[key] rescue nil)

    comparator = block || :==.to_proc

    if s_val.is_a?(Hash) && o_val.is_a?(Hash)
      int = deep_intersect(s_val, o_val, &block)
      if !int.empty?
        empty[key] = int
      end
    elsif comparator.call(s_val, o_val)
      empty[key] = s_val
    end
  end

  empty
end


p deep_intersect(dir_hash, database_hash)
=> {:HASHES=>{:file1=>{:"1"=>"1"}, :file2=>{:"2"=>"4"}}}