This time I would like to provide another solution: normalized -> keep the original key value pairs -> grab the original key, which has more values ββas the key for the difference.
h1 = {"Cat" => 100, "Dog" => 5, "Bird" => 2, "Snake" => 10} h1.default = 0 h2 = {"cat" => 50, "dog" => 3, "BIRD" => 4, "Mouse" => 75, "Snake" => 10} h2.default = 0 h3 = {"Cat" => 50, "Dog" => 2, "BIRD" => -2, "Mouse" => -75} class Hash def difference(subtrahend) # create a hash which contains all normalized keys all_pairs = (self.keys.map{|x| x.downcase} + subtrahend.keys.map{|x| x.downcase}).uniq.inject({}) do |pairs, key| pairs[key] = [] pairs end #=> {"mouse"=>[], "cat"=>[], "snake"=>[], "bird"=>[], "dog"=>[]} # push original key value pairs into array which is the value of just created hash [self, subtrahend].each_with_index do |hsh, idx| hsh.each_pair { |k, v| all_pairs[k.downcase].push([k, v]) } all_pairs.each_value { |v| v.push([nil, 0]) if v.size == idx } end #=> {"mouse"=>[[nil, 0], ["Mouse", 75]], "cat"=>[["Cat", 100], ["cat", 50]], "snake"=>[["Snake", 10], ["Snake", 10]], "bird"=>[["Bird", 2], ["BIRD", 4]], "dog"=>[["Dog", 5], ["dog", 3]]} results = {} all_pairs.each_value do |values| diff = values[0][1] - values[1][1] # always take the key whose value is larger if diff > 0 results[values[0][0]] = diff elsif diff < 0 results[values[1][0]] = diff end end return results end end puts h1.difference(h2).inspect #=> {"Cat" => 50, "Dog" => 2, "BIRD" => -2, "Mouse" => -75} h1.difference(h2) == h3 ? puts("Pass") : puts("Fail") #=> "Pass"
According to what you described, this one does a pretty good job. The result is exactly what you showed (the key does not normalize in the final result, but depends on whose value is greater).