简体   繁体   中英

Find missing keys from a nested hash in comparison to another nested hash

I have two nested hashes (hash1, hash2) which incidentally happen to be hashes generated from yml files. I need to find all the keys (the complete parent chain) which are present in hash1 but not in hash2.

Given these two hashes, the output should be hash_diff.

hash1 = {"A" => 1, "B" => {"C" => 2, "D" => 3} , "E" => 1} 
hash2 = {"A" => 1, "B" => {"C" => 2} }
hash_diff = {"B" => {"D" => 3}, "E" => 1} 

Note that I want something like a hash diff, which takes only the keys into account, and not the values.

Here is the solution. Although I have modified the original hash1
So the usage is:

hash_diff(hash1,hash2)
hash_diff_var = hash1

def self.hash_diff_helper(hash1,hash2)
    hash1.each_pair do |k,v|
      if v.is_a?(Hash) && hash2.key?(k)
        hash_diff_helper(v,hash2[k])
      elsif !v.is_a?(Hash) && hash2.key?(k)
        hash1.delete(k)
      end
    end
  end

  def self.hash_diff(hash1,hash2)
    hash_diff_helper(hash1,hash2)
    hash1.select!{|k,v| v.present?}
  end

I'd monkey patch Hash to get functionailty that you want, so essentially a merge that returns nil when doesn't exist in hash2, then implement compact on hash:

class ::Hash
     def deep_nil_merge(second)
        merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : nil }
        self.merge(second, &merger)
     end

  def compact
    delete_if{|k, v|

      (v.is_a?(Hash) and v.respond_to?('empty?') and v.compact.empty?) or
          (v.nil?)  or
          (v.is_a?(String) and v.empty?)
    }
  end


end

Then run

hash1.deep_nil_merge(hash2).compact

There are a couple of gems that might help you achieve this.

If you want just a pure diff https://github.com/Blargel/easy_diff is a nice option. It gives you both what has been added and removed to make the difference.

A more robust option is https://github.com/liufengyun/hashdiff which doesn't modify the Hash object but returns an array of all the differences in dot notation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM