Even I understand correctly what you want to do, consider using a different data structure.
color_hash = { sky: "blue", pothole: "black", curtain: "blue",
pavement: "black", roadblock: "red" }
You could use Enumerable#group_by:
color_hash.group_by(&:last).tap { |h| h.each_key { |k| h[k].map!(&:first) } }
#=> {"blue"=>[:sky, :curtain], "black"=>[:pothole, :pavement],
# "red"=>[:roadblock]}
or Hash#update:
color_hash.each_with_object({}) { |(k,v),h|
h.update(v=>[k]) { |_,o,n| o+n } }
#=> {"blue"=>[:sky, :curtain], "black"=>[:pothole, :pavement],
# "red"=>[:roadblock]}
This uses the form of Hash#update
(aka merge!
) that employs a block to determine the values of keys that are present in both hashes being merged. Here { |_,o,n| o+n }
is that block, where (the local variable) _
is the key (rather than, say, k
, to tell the reader that it's not used in the calculation), o
("old") is the value of the hash h
for that key and n
is the value of the hash being merged in for that key.