Turning a Hash of Arrays into an Array of Hashes in Ruby

Convert hash to array of hashes

Leveraging Array#transpose and Array#to_h

keys = list.keys
list.values.transpose.map { |v| keys.zip(v).to_h }

Turning a Hash of Arrays into an Array of Hashes in Ruby

This solution works with arbitrary numbers of values (val1, val2...valN):

{:a => ["val1", "val2"], :b => ["valb1", "valb2"]}.inject([]){|a, (k,vs)| 
vs.each_with_index{|v,i| (a[i] ||= {})[k] = v}
a
}
# => [{:a=>"val1", :b=>"valb1"}, {:a=>"val2", :b=>"valb2"}]

[{:a=>"val1", :b=>"valb1"}, {:a=>"val2", :b=>"valb2"}].inject({}){|a, h|
h.each_pair{|k,v| (a[k] ||= []) << v}
a
}
# => {:a=>["val1", "val2"], :b=>["valb1", "valb2"]}

Merge hash of arrays into array of hashes

I suggest writing the code to permit arbitrary numbers of attributes. It's no more difficult than assuming there are two (:name and :surname), yet it provides greater flexibility, accommodating, for example, future changes to the number or naming of attributes:

def squish(h)
keys = h.keys.map(&:to_s)
h.values.transpose.map { |a| keys.zip(a).to_h }
end

h = { name:    ["John", "Jane", "Chris"],
surname: ["Doe", "Doe", "Smith"],
age: [22, 34, 96]
}

squish(h)
#=> [{"name"=>"John", "surname"=>"Doe", "age"=>22},
# {"name"=>"Jane", "surname"=>"Doe", "age"=>34},
# {"name"=>"Chris", "surname"=>"Smith", "age"=>96}]

The steps for the example above are as follows:

b = h.keys
#=> [:name, :surname, :age]
keys = b.map(&:to_s)
#=> ["name", "surname", "age"]
c = h.values
#=> [["John", "Jane", "Chris"], ["Doe", "Doe", "Smith"], [22, 34, 96]]
d = c.transpose
#=> [["John", "Doe", 22], ["Jane", "Doe", 34], ["Chris", "Smith", 96]]
d.map { |a| keys.zip(a).to_h }
#=> [{"name"=>"John", "surname"=>"Doe", "age"=>22},
# {"name"=>"Jane", "surname"=>"Doe", "age"=>34},
# {"name"=>"Chris", "surname"=>"Smith", "age"=>96}]

In the last step the first value of b is passed to map's block and the block variable is assigned its value.

a = d.first
#=> ["John", "Doe", 22]
e = keys.zip(a)
#=> [["name", "John"], ["surname", "Doe"], ["age", 22]]
e.to_h
#=> {"name"=>"John", "surname"=>"Doe", "age"=>22}

The remaining calculations are similar.

transform array of arrays in array of hash

array = [
[ 1, "name1" ],
[ 2, "name2" ],
[ 3, "name3" ],
[ 4, "name4" ]
]
array.map { |e| ['id', 'name'].zip(e).to_h }
#⇒ [
# {"id"=>1, "name"=>"name1"},
# {"id"=>2, "name"=>"name2"},
# {"id"=>3, "name"=>"name3"},
# {"id"=>4, "name"=>"name4"}
# ]

The only interesting here is Enumerable#zip, that “merges” arrays.

Convert array of hashes to array

a=[{:code=>"404"}, {:code=>"302"}, {:code=>"200"}] 
puts a.map{|x|x.values}.flatten.inspect

output

["404", "302", "200"]

Convert array of hashes to single hash with values as keys

This should do what you want

countries.each_with_object({}) { |country, h| h[country[:country].to_sym] = country[:cost] }
=> {:england=>12.34, :scotland=>56.78}


Related Topics



Leave a reply



Submit