How would I reverse the elements in the hash, keeping the same values and keys, but reversing their order in the hash.
Like so:
{ \"4\" => \"happiness
In pure ruby, you can do it by hash.map(&:reverse).to_h
or hash.reverse_each.to_h
In rails, you can do it by hash.invert
reversed_h = Hash[h.to_a.collect(&:reverse)]
In Ruby 1.8.7, the order of elements in a hash is documented to be not under our control, so none of the above methods work. In Ruby 1.9.3, things work and are documented in the way that the other answers rely upon.
$ irb1.8 h = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" } Hash[h.to_a().reverse()] => {"lala"=>"54", "1"=>"spider", "10"=>"cool", "4"=>"happiness"} quit $ irb1.9.1 h = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "spider" } Hash[h.to_a().reverse()] =>{"1"=>"spider", "lala"=>"54", "10"=>"cool", "4"=>"happiness"}
The Ruby 1.8.7 way was ingrained so firmly for me that I misunderstood the question for quite some time. I thought it requested a way to Hash#invert: ie to transform the hash such that the range maps to the domain. That method discards duplicates. Luís Ramalho proffers a method that doesn't, but it's a bit clunky. This is a little shorter:
$ irb def invertWithDuplicates(original) inverse = Hash.new() { |hash, key| hash[key] = []; } original.each_pair() { |key, value| inverse[value].push(key); } return inverse end h = { "4" => "happiness", "10" => "cool", "lala" => "54", "1" => "cool" } invertWithDuplicates(h) => {"happiness"=>["4"], "cool"=>["1", "10"], "54"=>["lala"]}
Sorry to drift away from the OP's intended topic, though I submit that this does fit the post's title "Reverse a hash in Ruby".