Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inverting a hash with array values

Tags:

ruby

For ease of authoring I'm writing my hash like this:

h = {
    :key1: [:val1, :val2, :val3],
    :key2: [:val4, :val5, :val6]
}

But everywhere I use it I need to look up the key associated with a value. Currently I'm doing the following to transform it:

h = Hash[*{
    :key1: [:val1, :val2, :val3],
    :key2: [:val4, :val5, :val6]
}.map {|key, vals| vals.map {|val| [val, key]}}.flatten]

Which gives me what I want:

{ :val1 => :key1, :val2 => key1, :val3 => key1, :val4 => key2, :val5 => :key2, :val6 => :key2 }

But is there a simpler way to achieve the same goal?

like image 974
ICR Avatar asked Jul 08 '13 10:07

ICR


People also ask

Can a Hash key be an Array?

A Hash is a dictionary-like collection of unique keys and their values. Also called associative arrays, they are similar to Arrays, but where an Array uses integers as its index, a Hash allows you to use any object type. Hashes enumerate their values in the order that the corresponding keys were inserted.

How do I reverse a Hash in Perl?

%nhash = reverse %hash; Note that with reverse, duplicate values will be overwritten. the reverse way is nice, but it has some cavets (pasted directly from the perl docs): If a value is duplicated in the original hash, only one of those can be represented as a key in the inverted hash.

How do you reverse a Hash in Ruby?

Ruby Hashes don't have a reverse! method. This is unfortunate, because since Ruby 1.9 Hashes preserve their order, so they should be sortable and reversible, but currently it's not implemented.


3 Answers

Array#product is pretty badass for this. :)

h = {
    key1: [:val1, :val2, :val3],
    key2: [:val4, :val5, :val6]
}

p Hash[h.flat_map {|k,v| v.product [k]}]
# {:val1=>:key1, :val2=>:key1, :val3=>:key1, :val4=>:key2, :val5=>:key2, :val6=>:key2}
like image 155
Chris Heald Avatar answered Oct 13 '22 05:10

Chris Heald


h = {
    :key1 => [:val1, :val2, :val3],
    :key2 => [:val4, :val5, :val6]
}

p Hash[h.flat_map{|k,v| v.zip [k]*v.size }]
# >> {:val1=>:key1, :val2=>:key1, :val3=>:key1, :val4=>:key2, :val5=>:key2, :val6=>:key2}
p Hash[h.flat_map{|k,v| v.zip [k].cycle }]
# >> {:val1=>:key1, :val2=>:key1, :val3=>:key1, :val4=>:key2, :val5=>:key2, :val6=>:key2}
like image 23
Arup Rakshit Avatar answered Oct 13 '22 05:10

Arup Rakshit


I was trying to do just this yesterday. This was my solution:

h = {
key1: [:val1, :val2, :val3],    
key2: [:val4, :val5, :val6],    
}  
=> {:key1=>[:val1, :val2, :val3], :key2=>[:val4, :val5, :val6]}

hp = {}
=> {}

h.each { |k, v| v.each{ |e| hp[e] = k } }
=> {:key1=>[:val1, :val2, :val3], :key2=>[:val4, :val5, :val6]}

hp
=> {:val1=>:key1,
:val2=>:key1,
:val3=>:key1,
:val4=>:key2,
:val5=>:key2,
:val6=>:key2}
like image 2
Johnsyweb Avatar answered Oct 13 '22 06:10

Johnsyweb