Your comment about motherboards and blueprints suggest that you are given something like
h = { :mb1=>:bp3, :mb_2=>:bp1, :mb3=>:bp3, :mb4=>:bp2, :mb5=>:bp1 }
and want to produce the hash
{ :bp3=>[:mb1, :mb3], :bp1=>[:mb_2, :mb5], :bp2=>[:mb4] }
One of many ways to do that is the following:
h.each_with_object({}) { |(k,v),g| (g[v] ||= []) << k }
See Enumerable#each_with_object, and to understand why I've written the block varaiables |(k,v),g|, see array decomposition.
This is a condensed translation of the following code (which I've salted with three puts statement to show the calculations being performed):
g = {}
h.each do |key_value_pair|
k, v = key_value_pair
puts "\nkey_value_pair = #{key_value_pair}, k = #{k}, v = #{v}"
puts "g[#{v}] set to [] because g[#{v}] == nil" if g[v].nil?
g[v] = [] if g[v].nil?
g[v] << k
puts "g after g[#{v}] << #{g}"
end
#=> {:mb1=>:bp3, :mb_2=>:bp1, :mb3=>:bp3, :mb4=>:bp2, :mb5=>:bp1}
The following is displayed:
key_value_pair = [:mb1, :bp3], k = mb1, v = bp3
g[bp3] set to [] because g[bp3] == nil
g after g[bp3] << {:bp3=>[:mb1]}
key_value_pair = [:mb_2, :bp1], k = mb_2, v = bp1
g[bp1] set to [] because g[bp1] == nil
g after g[bp1] << {:bp3=>[:mb1], :bp1=>[:mb_2]}
key_value_pair = [:mb3, :bp3], k = mb3, v = bp3
g after g[bp3] << {:bp3=>[:mb1, :mb3], :bp1=>[:mb_2]}
key_value_pair = [:mb4, :bp2], k = mb4, v = bp2
g[bp2] set to [] because g[bp2] == nil
g after g[bp2] << {:bp3=>[:mb1, :mb3], :bp1=>[:mb_2], :bp2=>[:mb4]}
key_value_pair = [:mb5, :bp1], k = mb5, v = bp1
g after g[bp1] << {:bp3=>[:mb1, :mb3], :bp1=>[:mb_2, :mb5], :bp2=>[:mb4]}