I am having a hard time figuring out how to make the next rows a hash with the key from the first row.
I have an array structured like this:
[["id", "name", "address"], [1, "James", "...."], [2, "John", "...."] ] To be:
[{ id : 1, name: "James", address: "..."}, ...] I used a gem "simple_xlsx_reader", I am extracting out only the first sheet.
wb.sheets.first.row and got a similar array output from above.
thanks!
23 Answers
arr = [["id", "name"], [1, "Jack"], [2, "Jill"]] [arr.first].product(arr.drop 1).map { |a| a.transpose.to_h } #=> [{"id"=>1, "name"=>"Jack"}, {"id"=>2, "name"=>"Jill"}] The steps:
b = [arr.first] #=> [["id", "name"]] c = arr.drop 1 #=> [[1, "Jack"], [2, "Jill"]] d = b.product(c) #=> [[["id", "name"], [1, "Jack"]], [["id", "name"], [2, "Jill"]]] d.map { |a| a.transpose.to_h } #=> [{"id"=>1, "name"=>"Jack"}, {"id"=>2, "name"=>"Jill"}] The first element of d passed to map's block is:
a = d.first [["id", "name"], [1, "Jack"]] The block calculation is therefore:
e = a.transpose #=> [["id", 1], ["name", "Jack"]] e.to_h #=> {"id"=>1, "name"=>"Jack"} 4This is what you're looking for:
arr = [["id", "name", "address"], [1, "James", "...."], [2, "John", "...."] ] keys, *values = arr values.map {|vals| keys.zip(vals).to_h } Enumerable#zip takes two arrays (the receiver and the argument) and "zips" them together, producing an array of tuples (two-element arrays) e.g.:
keys = [ "foo", "bar", "baz" ] values = [ 1, 2, 3 ] p keys.zip(values) # => [ [ "foo", 1 ], [ "bar", 2 ], [ "baz", 3 ] ] Array#to_h takes an array of tuples and turns it into a hash.
If you're using a version of Ruby earlier than 2.1 you'll need to use Hash[ *keys.zip(vals) ] instead.
P.S. If you want symbol keys instead of string keys you'll want to perform that conversion before the map, e.g.:
keys = keys.map(&:to_sym) Or, if you don't mind modifying the original array:
keys.map!(&:to_sym) 2You can try this very simple one line that make your work
arr =[["id", "name", "address"], [1, "James", "add 1"], [2, "John", "add2"] ] arr.map {|a| arr.first.zip(a).to_h unless a == arr.first }.compact 0