From: Stefano Mioli Date: 2011-07-16T03:32:24+09:00 Subject: Re: Comparing hashes based on their keys On 7/15/11 6:04 PM, Robert Klemme wrote: >> 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 > > It seems your spec is not very precise because your bullet list mixes > AND and OR. I assume you meant > > Two objects o1 and o2 are considered equal for this relation if and only if > > ( o1 is nil AND o2 is nil ) OR > ( o1 is a Hash AND o2 is a Hash AND > o1.keys == o2.keys AND > for each key k ( o1[k] is not a Hash OR > o2[k] is not a Hash OR > o1[k] equals o2[k] according to this relation ) ) Exactly. Sorry about the confusion. >> def compare(hash1, hash2) > > I would rename arguments because these need not be Hashes. Fair enough. >> 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 > > Hm, I'd probably remove #all?, #any? and the like and code conditions > directly - especially since you are always dealing with two items > because it's likely faster. Your code creates a lot of temporary > Arrays along the way. True. On the other hand, the hashes will be fairly small, so performance wasn't the main goal. That, and I the fact that I find: [x, y].all? {|x| x.is_a?(Hash) } to be a bit more nice-looking than if x.is_a?(Hash) && y.is_a?(Hash) But you make a very good point, thanks. > Btw, I believe your implementation misses the case where hash2's key > set is a superset of hash1's, i.e. contains additional keys. True. I posted again the link to the gist with a revised version according to Rob's suggestions. Thank you very much, Robert. Ah, there are so many things to learn. -- Stefano Mioli