Create a hash from an array using group_by

237 views Asked by At

I have the following array

ages = [["a", 15],["b", 16], ["c", 15], ["d", 16], ["e", 17], ["f", 20]]

I have to create a hash with ages as values such that it looks like this

{15 => ["a","c"], 16=> ["b","d]....}

when I run the group_by method:

puts ages.group_by {|list| list[1]}

this is what i get:

{15=>[["a", 15], ["c", 15]], 16=>[["b", 16], ["d", 16]], 17=>[["e", 17]], 20=>[["f", 20]]}

I'd really appreciate it if you can clarify how to make this cleaner and get the values as an array of names with same ages.

2

There are 2 answers

2
ggorlen On

The first thing that comes to mind is

irb(main):012:0> ages.group_by {|e| e[1]}.map {|k, v| [k, v.map(&:first)]}.to_h
=> {15=>["a", "c"], 16=>["b", "d"], 17=>["e"], 20=>["f"]}

Here we map the hash to key-value pairs, map the values of each pair to first elements then convert the pairs back to a hash.

0
Cary Swoveland On
ages = [["a", 15],["b", 16], ["c", 15], ["d", 16], ["e", 17], ["f", 20]]

You can simplify your first step:

ages.group_by(&:last)
  #=> {15=>[["a", 15], ["c", 15]],
  #    16=>[["b", 16], ["d", 16]],
  #    17=>[["e", 17]],
  #    20=>[["f", 20]]}

You then need only transform the values to the desired arrays:

ages.group_by(&:last).transform_values { |arr| arr.map(&:first) }
  #=> {15=>["a", "c"],
  #    16=>["b", "d"],
  #    17=>["e"],
  #    20=>["f"]}

When

arr = [["a", 15], ["c", 15]]

for example,

arr.map(&:first)
  #=> ["a", "c"] 

See Hash#transform_values.