Hi list,
let’s say we want to write a method that compares two hashes for
equality based on their keys.
Each key is a symbol, and the corrisponding value can either be a string
or another hash with this same properties.
Two hashes, let’s call them h1 and h2, are to be considered equal if:
-
they have the same keys
-
h1[:x] and h2[:x] are both hashes, and they are equal according to the
very same rules you are reading -
they are both nil
In short, we only care about the values when they are hashes.
If they are strings, we don’t care whether they are equal or not.
To make an example, when fed these two hashes the method should return
true:
h1 = {
:one => “one”,
:two => “two”,
:three => {
:alpha => “alpha”,
:bravo => “bravo”,
:charlie => “charlie”
}
}
h2 = {
:one => “whatever”,
:two => “hey”,
:three => {
:alpha => “zulu”,
:bravo => “oscar”,
:charlie => “brown”
}
}
When fed these other two arrays, the method should return false:
h3 = h1
h4 = {
:one => “one”,
:two => “two”,
:three => {
:alpha => “alpha”,
:bravo => “bravo”,
}
}
The difference is that Ole :charlie is missing in h2.
The values don’t change to make it clear that we don’t care about them.
I came up with the following implementation that seems to work (at least
according to the specs I wrote), but what I would like to ask is if it
could be any simpler/more idiomatic/more elegant.
Corner cases that one might spot are also good to know about.
def compare(hash1, hash2)
args = [hash1, hash2]
return true if args.all? {|h| h.nil?}
return false if args.one? {|h| h.nil?}
hash1.each_key do |k|
values = [hash1[k], hash2[k]]
if values.all? {|h| h.is_a?(Hash)}
return compare(*values)
else
return false if values.one? {|value| value.nil? }
end
end
true
end
Should the code turn out to be unreadable, I posted it here[0] too.
[0] = Comparing hashes based on their keys · GitHub
Thanks in advance.