Convert hash to array of hashes

  • A+
Category:Languages

I have hash, all its values are arrays, like this:

list = { letter:  ['a', 'b', 'c'],          number:  ['one', 'two', 'three'],          fruit:   ['apple', 'pear', 'kiwi'],          car:     ['vw', 'mb', 'bmw'],          state:   ['la', 'ny', 'fl'],          color:   ['red', 'white', 'black'],          tree:    ['oak', 'pine', 'maple'],          animal:  ['cat', 'dog', 'rat'],          clothes: ['tie', 'sock', 'glove'] } 

In fact this hash could have more keys and values could be larger, but always sizes of every value are the same (in this case - three).

I want to convert this hash to array of hashes.

Each hash will have all keys of origin hash and respective value.

So finally I want to have:

list = [   { letter: 'a', number: 'one', fruit: 'apple', car: 'vw', state: 'la',     color: 'red', tree: 'oak', animal: 'cat', clothes: 'tie' },    { letter: 'b', number: 'two', fruit: 'pear', car: 'mb', state: 'ny',     color: 'white', tree: 'pine', animal: 'dog', clothes: 'sock' },    { letter: 'c', number: 'three', fruit: 'kiwi', car: 'bmw', state: 'fl',     color: 'black', tree: 'elm', animal: 'rat', clothes: 'glove' } ] 

What's the best way to do it?

 


[list.keys].product(list.values.transpose).map { |a| a.transpose.to_h }    #=> [{:letter=>"a", :number=>"one", :fruit=>"apple", :car=>"vw",     #     :state=>"la", :color=>"red", :tree=>"oak", :animal=>"cat",    #     :clothes=>"tie"},    #    {:letter=>"b", :number=>"two", :fruit=>"pear", :car=>"mb",    #     :state=>"ny", :color=>"white", :tree=>"pine", :animal=>"dog",    #     :clothes=>"sock"},    #    {:letter=>"c", :number=>"three", :fruit=>"kiwi", :car=>"bmw",    #     :state=>"fl", :color=>"black", :tree=>"maple", :animal=>"rat",     #     :clothes=>"glove"}] 

Suppose list were defined as follows.

list = {   letter:  ['a',     'b'   ],   number:  ['one',   'two' ],   fruit:   ['apple', 'pear'],   car:     ['vw',    'mb'  ] } 

The steps would be as follows.

b = [list.keys]   #=> [[:letter, :number, :fruit, :car, :state, :color, :tree,   #     :animal, :clothes]] c = list.values   #=> [["a", "b", "c"], ["one", "two", "three"], ["apple", "pear", "kiwi"],   #    ["vw", "mb", "bmw"], ["la", "ny", "fl"], ["red", "white", "black"],   #    ["oak", "pine", "maple"], ["cat", "dog", "rat"],   #    ["tie", "sock", "glove"]] d = c.transpose   #=> [["a", "one", "apple", "vw", "la", "red", "oak", "cat", "tie"],   #    ["b", "two", "pear", "mb", "ny", "white", "pine", "dog", "sock"],   #    ["c", "three", "kiwi", "bmw", "fl", "black", "maple", "rat", "glove"]] e = b.product(d)   #=> [[[:letter, :number, :fruit, :car, :state, :color, :tree, :animal,   #      :clothes],   #     ["a", "one", "apple", "vw", "la", "red", "oak", "cat", "tie"]],   #    [[:letter, :number, :fruit, :car, :state, :color, :tree, :animal,   #      :clothes],   #     ["b", "two", "pear", "mb", "ny", "white", "pine", "dog", "sock"]],   #    [[:letter, :number, :fruit, :car, :state, :color, :tree,   #      :animal, :clothes],    #     ["c", "three", "kiwi", "bmw", "fl", "black", "maple", "rat",   #      "glove"]]] e.map { |a| a.transpose.to_h }   #=> [{:letter=>"a", :number=>"one", :fruit=>"apple", :car=>"vw",   #     :state=>"la", :color=>"red", :tree=>"oak", :animal=>"cat",   #     :clothes=>"tie"},   #    {:letter=>"b", :number=>"two", :fruit=>"pear", :car=>"mb",   #     :state=>"ny", :color=>"white", :tree=>"pine", :animal=>"dog",   #     :clothes=>"sock"}, {:letter=>"c", :number=>"three", :fruit=>"kiwi",   #     :car=>"bmw", :state=>"fl", :color=>"black", :tree=>"maple",    #     :animal=>"rat", :clothes=>"glove"}] 

Let's look at the last step more closely. map passes the first element of e to the block and sets the block variable a to its value:

a = e.first   #=> [[:letter, :number, :fruit, :car, :state, :color, :tree,   #     :animal, :clothes],   #    ["a", "one", "apple", "vw", "la", "red", "oak", "cat", "tie"]] 

The block calculation is as follows.

f = a.transpose   #=> [[:letter, "a"], [:number, "one"], [:fruit, "apple"], [:car, "vw"],   #    [:state, "la"], [:color, "red"], [:tree, "oak"], [:animal, "cat"],   #    [:clothes, "tie"]] f.to_h   #=> {:letter=>"a", :number=>"one", :fruit=>"apple", :car=>"vw",   #    :state=>"la", :color=>"red", :tree=>"oak", :animal=>"cat",   #    :clothes=>"tie"} 

The remaining calculations for e.map { |a| a.transpose.to_h } are similar.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: