Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changes between two hashes in ruby

I have two hashes with the below format

mydetails[x['Id']] = x['Amount']

this would contain data like

hash1 = {"A"=>"0", "B"=>"1","C"=>"0", "F"=>"1"}
hash2 = {"A"=>"0", "B"=>"3","C"=>"0", "E"=>"1"}

I am expecting an output something like:

Differences in hash: "B, F, E"

Any help is very much appreciated.

like image 915
d_luffy_de Avatar asked Dec 20 '16 13:12

d_luffy_de


2 Answers

This solution might be a bit easier to understand :

(hash1.keys | hash2.keys).select{ |key| hash1[key] != hash2[key] }

Array#| returns the set union of 2 arrays. It's equivalent to :

(hash1.key + hash2.keys).uniq

NOTE: If you want to consider that {} and {b: nil} differ on :b even though they return the same value for :b key :

(hash1.keys | hash2.keys).reject do |key|
  hash1.has_key?(key) &&
  hash2.has_key?(key) &&
  hash1[key] == hash2[key]
end
like image 189
Eric Duminil Avatar answered Nov 01 '22 00:11

Eric Duminil


Hash#merge with a block would do:

hash1.merge(hash2) { |k, v1, v2| v1 == v2 ? :equal : [v1, v2] }
     .reject { |_, v| v == :equal }
     .keys
#⇒ ["B", "F", "E"]

Note: This will work even for a hash containing a value of :equal (to address the comment below), because the merge result would contain a value of [:equal, nil], not simply the value :equal. However, to simplify the whole thing and avoid confusion, in Ruby 2.4+ you could use Hash#compact like this:

hash1.merge(hash2) { |_k, v1, v2| v1 == v2 ? nil : :different }
     .compact.keys
like image 25
Aleksei Matiushkin Avatar answered Nov 01 '22 00:11

Aleksei Matiushkin