Reputation: 15248
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?
Upvotes: 3
Views: 3125
Reputation: 15248
Using Array::new
as new array "builder" and Enumerable#each_with_object
as every item "builder"
Array.new(list.first.last.size) do |index|
list.each_with_object({}) { |(key, values), new_item| new_item[key] = values[index] }
end
Upvotes: 0
Reputation: 110675
[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]]
c = list.values
#=> [["a", "b"], ["one", "two"], ["apple", "pear"], ["vw", "mb"]]
d = c.transpose
#=> [["a", "one", "apple", "vw"],
# ["b", "two", "pear", "mb"]]
e = b.product(d)
#=> [[[:letter, :number, :fruit, :car], ["a", "one", "apple", "vw"]],
# [[:letter, :number, :fruit, :car], ["b", "two", "pear", "mb"]]]
e.map { |a| a.transpose.to_h }
#=> [{:letter=>"a", :number=>"one", :fruit=>"apple", :car=>"vw"},
# {:letter=>"b", :number=>"two", :fruit=>"pear", :car=>"mb"}]
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],
# ["a", "one", "apple", "vw"]]
The block calculation is as follows.
f = a.transpose
#=> [[:letter, "a"], [:number, "one"], [:fruit, "apple"], [:car, "vw"]]
f.to_h
#=> {:letter=>"a", :number=>"one", :fruit=>"apple", :car=>"vw"}
The remaining calculations for e.map { |a| a.transpose.to_h }
are similar.
Upvotes: 9
Reputation: 11183
Just to play with Enumerable#each_with_object
:
list.values.transpose.each_with_object([]) { |v, a| a << v.each_with_index.with_object({}) { |(vv, i), h| h[list.keys[i]] = vv } }
Upvotes: 0
Reputation: 5252
All in one:
list.map{|k,v| [k].product(v)}.transpose.map(&:to_h)
The idea is to use each key product its values, map out, transpose, then convert to hash by to_h
.
Upvotes: 3
Reputation: 5313
Leveraging Array#transpose and Array#to_h
keys = list.keys
list.values.transpose.map { |v| keys.zip(v).to_h }
Upvotes: 5
Reputation: 5552
Try following code,
arr = []
3.times { |x| arr[x] = {}; list.each { |k,v| arr[x][k] = v[x] } }
arr.inspect
Output will be
=> [{: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"}]
Upvotes: 2