5

I have a 2D array with each row like:

['John', 'M', '34']

I want to map into an array of Hash with each hash like:

{:Name=>"John", :Gender=>"M", :Age=>"34"}

Is there an elegant way of doing that?

0

5 Answers 5

8
array_of_rows.map { |n,g,a| { Name: n, Gender: g, Age: a } }

or

array_of_rows.map { |row| %i{Name Gender Age}.zip(row).to_h }

They produce the same result, so pick the one you find clearer. For example, given this input:

array_of_rows = [
  ['John', 'M', '34'],
  ['Mark', 'M', '49']
]

either expression will yield this output:

[{:Name=>"John", :Gender=>"M", :Age=>"34"}, 
 {:Name=>"Mark", :Gender=>"M", :Age=>"49"}]
Sign up to request clarification or add additional context in comments.

2 Comments

When I see problems like this I generally ask myself, "What if the data changes in future, the number of keys, for example?". Best to avoid having to change the code, of course, so I prefer #2, but would not hardwire %i{Name Gender Age}.
Sure. Ideally you'd have some metadata associated with the array you could use instead of hard-coding the key names; perhaps it was read from a CSV file, and the first row contains headers that can be repurposed.
4

You could try using zip and then to_h (which stands for to hash)

For example:

[:Name, :Gender, :Age].zip(['John', 'M', '34']).to_h
=> {:Name=>"John", :Gender=>"M", :Age=>"34"}

Read more about zip here

And read about to_h here

Comments

4
people = [['John', 'M', '34']]
keys = %i{Name Gender Age}

hashes = people.map { |person| keys.zip(person).to_h }
# => [{:Name=>"John", :Gender=>"M", :Age=>"34"}]

Basically the way I turn combine two arrays into a hash (one with keys, one with values) is to use Array#zip. This can turn [1,2,3] and [4,5,6] into [[1,4], [2,5], [3,6]]

This structure can be easily turned into a hash via to_h

Comments

1
array_of_rows = [
  ['John', 'M', '34'],
  ['Mark', 'M', '49']
]

keys = ['Name', 'Gender', 'Age']

[keys].product(array_of_rows).map { |k,v| k.zip(v).to_h }
  #=> [{"Name"=>"John", "Gender"=>"M", "Age"=>"34"},
  #    {"Name"=>"Mark", "Gender"=>"M", "Age"=>"49"}]

or

keys_cycle = keys.cycle
array_of_rows.map do |values|
  values.each_with_object({}) { |value, h| h[keys_cycle.next]=value }
do

Comments

0

Here is one more way to do this

array_of_rows = [
  ['John', 'M', '34'],
  ['Mark', 'M', '49']
]

keys = [:Name, :Gender, :Age]

array_of_rows.collect { |a| Hash[ [keys, a].transpose] }
#=>[{:Name=>"John", :Gender=>"M", :Age=>"34"}, {:Name=>"Mark", :Gender=>"M", :Age=>"49"}]

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.