Tony DiNitto
Tony DiNitto

Reputation: 1239

Inverting a hash value (that's an array) into new individual keys

I have the following:

lumpy_hash = { 1 => ["A", "B"] }

then if I invoke Hash#invert on this hash, I'd like to get:

lumpy_hash = {"A" => 1, "B" => 1}

I don't get that from using Hash#invert. Any ideas on doing this? I'm not sure if I should try Hash#map or Hash#invert.

Upvotes: 0

Views: 210

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110685

There are many ways to do this. Here is one:

Hash[lumpy_hash.map { |k,v| v.product([k]) }.first]
 #=> {"A"=>1, "B"=>1} 

I don't think the method Hash#invert is useful here.

The steps:

enum = lumpy_hash.map
  #=> #<Enumerator: {1=>["A", "B"]}:map> 
k,v = enum.next
  #=> [1, ["A", "B"]] 
k #=> 1 
v #=> ["A", "B"] 
a = v.product([k])
  #=> ["A", "B"].product([1])
  #=> [["A", 1], ["B", 1]] 
Hash[a]
  #=> {"A"=>1, "B"=>1}

Here's another way that makes use of a hash's default value. This one is rather interesting:

key,value = lumpy_hash.to_a.first
  #=> [1, ["A","B"]]
Hash.new { |h,k| h[k]=key }.tap { |h| h.values_at(*value) }
  #=> {"A"=>1,"B"=>1}

Object#tap passes an empty hash to its block, assigning it to the block variable h. The block returns h after adding three key-value pairs, each having a value equal to the hash's default value. It adds the pairs merely by computing the values of keys the hash doesn't have!

Upvotes: 5

user12341234
user12341234

Reputation: 7213

Here's another, more pedestrian, method:

lumpy_hash.flat_map{|k,vs| vs.map{|v| {v => k}}}.reduce(&:merge)
 => {"A"=>1, "B"=>1}

Upvotes: 1

Related Questions