Q:

How to invert a hash, maintaining duplicate keys

From an initial hash t:
t = {"1"=>1, "2"=>2, "3"=>2, "6"=>3, "5"=>4, "4"=>1, "8"=>2, "9"=>2, "0"=>1, "7"=>1}

I need to swap the keys and values as follows:
t = {"1"=>1, "2"=>2, "3"=>2, "6"=>3, "5"=>4, "1"=>4, "8"=>2, "9"=>2, "1"=>0, "1"=>7}

While maintaining the structure of the hash (ie, without collapsing duplicate keys). 
Then I'll make an array out of this hash. 
Is there a way to do this? I tried this:
t.find_all{ |key,value| value == 1 }   # pluck all elements with values of 1
#=> [["1", 1], ["4", 1], ["0", 1], ["7", 1]]

But it returns a new array, and the initial hash isn't changed.
The following doesn't work either:
t.invert.find_all{ |key,value| value == 1 }  
#=> []

A:

Here's a way to do this:
>> t = {"1" => 1, "2" => 2, "3" => 2, "6" => 3, "5" => 4, "4" => 1, "8" => 2, "9" => 2, "0" => 1, "7" => 1}

Hash#compare_by_identity allows for keys that are duplicates by value but unique by object id:
>> h = Hash.new.compare_by_identity
>> t.each_pair{ |k,v| h[v.to_s] = v.to_i }

The inverse hash of t:
>> h
#=> {"1" => 1, "2" => 2, "2" => 3, "3" => 6, "4" => 5, "1" => 4, "2" => 8, "2" => 9, "1" => 0, "1" => 7} 

You can then use find_all to retrieve an array of elements without mutating h:
>> h.find_all{ |k,_|  k == "1" }
#=> [["1", 1], ["1", 1], ["1", 1], ["1", 1]]

or keep_if to return the mutated h:
>> h.keep_if{ |k,_|  k == "1"  }        
#=> {"1"=>1, "1"=>1, "1"=>1, "1"=>1}
>> h
#=> {"1"=>1, "1"=>1, "1"=>1, "1"=>1}

Note that this solution assumes you want to maintain the pattern of string keys and integer values in your hash. If you require integer keys, compare_by_identity won't be helpful to you.

