How do I compare two hashes?
I am trying to compare two Ruby Hashes using the following code:
#!/usr/bin/env ruby
require "yaml"
require "active_support"
file1 = YAML::load(File.open('./en_20110207.yml'))
file2 = YAML::load(File.open('./locales/en.yml'))
arr = []
file1.select { |k,v|
file2.select { |k2, v2|
arr << "#{v2}" if "#{v}" != "#{v2}"
}
}
puts arr
The output to the screen is the full file from file2. I know for a fact that the files are different, but the script doesn't seem to pick it up.
You can compare hashes directly for equality:
hash1 = {'a' => 1, 'b' => 2}
hash2 = {'a' => 1, 'b' => 2}
hash3 = {'a' => 1, 'b' => 2, 'c' => 3}
hash1 == hash2 # => true
hash1 == hash3 # => false
hash1.to_a == hash2.to_a # => true
hash1.to_a == hash3.to_a # => false
You can convert the hashes to arrays, then get their difference:
hash3.to_a - hash1.to_a # => [["c", 3]]
if (hash3.size > hash1.size)
difference = hash3.to_a - hash1.to_a
else
difference = hash1.to_a - hash3.to_a
end
Hash[*difference.flatten] # => {"c"=>3}
Simplifying further:
Assigning difference via a ternary structure:
difference = (hash3.size > hash1.size) \
? hash3.to_a - hash1.to_a \
: hash1.to_a - hash3.to_a
=> [["c", 3]]
Hash[*difference.flatten]
=> {"c"=>3}
Doing it all in one operation and getting rid of the difference
variable:
Hash[*(
(hash3.size > hash1.size) \
? hash3.to_a - hash1.to_a \
: hash1.to_a - hash3.to_a
).flatten]
=> {"c"=>3}
You can try the hashdiff gem, which allows deep comparison of hashes and arrays in the hash.
The following is an example:
a = {a:{x:2, y:3, z:4}, b:{x:3, z:45}}
b = {a:{y:3}, b:{y:3, z:30}}
diff = HashDiff.diff(a, b)
diff.should == [['-', 'a.x', 2], ['-', 'a.z', 4], ['-', 'b.x', 3], ['~', 'b.z', 45, 30], ['+', 'b.y', 3]]