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] = https://gist.github.com/1084916
Thanks in advance.
···
--
Stefano