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.