Make the first row as the keys for hash for the next rows?

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!

2

3 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"} 
4

This 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) 
2

You 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

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like