user13350731
user13350731

Reputation: 97

Converting an array to hash - Ruby

I have the following array and I want to convert it a hash with keys as age and values like the name of the person. Additionally, I want to make sure that folks of the same age belong to the same key.

ages = [ ['alpha', 20], ['beta',21], ['charlie',23], ['delta', 20] , ['gamma', 23]]

how do I convert the above into a hash like below?

eg - {20 => ['alpha','delta'] } etc.

i have tried the following code but i am getting stuck beyond this point:

hash = Hash[ages.collect {|item| [item[1], item[0]]} ]

pp hash

thank you.

Upvotes: 0

Views: 250

Answers (4)

max pleaner
max pleaner

Reputation: 26758

Yet another way to do this: Hash#transform_values with Enumerable#group_by

ages.
  group_by(&:second).
  transform_values { |entries| entries.map(&:first) }
# => {20=>["alpha", "delta"], 21=>["beta"], 23=>["charlie", "gamma"]}

Upvotes: 2

Cary Swoveland
Cary Swoveland

Reputation: 110665

ages.each_with_object({}) do |(str,x),h|
  (h[x] ||= []) << str
end
  #=> {20=>["alpha", "delta"], 21=>["beta"], 23=>["charlie", "gamma"]}

h[x] ||= [] expands to

h[x] = h[x] || []

If h does not have a key x this becomes

h[x] = nil || []

causing h[x] to be set equal to an empty array, after which h[x] << str is executed.

Expressing the block variables as |(str,x),h| makes use of Ruby's array decomposition:

enum = ages.each_with_object({})
  #=> #<Enumerator: [["alpha", 20], ["beta", 21], ["charlie", 23],
  #     ["delta", 20], ["gamma", 23]]:each_with_object({})> 
(str,x),h = enum.next
  #=> [["alpha", 20], {}] 
str
  #=> "alpha" 
x #=> 20 
h #=> {} 
(h[x] ||= []) << str
  #=> ["alpha"] 

(str,x),h = enum.next
  #=> [["beta", 21], {20=>["alpha"]}] 

and so on.

Upvotes: 1

Oleksandr Holubenko
Oleksandr Holubenko

Reputation: 4440

One of the possible solutions is to use:

hash = ages.each_with_object(Hash.new {|h,k| h[k] = [] }) do |obj, res|
  res[obj.last] << obj.first
end

=> {20=>["alpha", "delta"], 21=>["beta"], 23=>["charlie", "gamma"]}
  1. Hash#default_proc
  2. Enumerable#each_with_object

Upvotes: 2

PhiAgent
PhiAgent

Reputation: 158

you can create the hash first and loop through the ages collecting members of similar ages into arrays.

hash = Hash.new{|h,k|h[k]=Array.new()}
ages.each do |age|
  hash[age.last]<<age.first
end
p hash #{20=>["alpha", "delta"], 21=>["beta"], 23=>["charlie", "gamma"]}

Upvotes: 1

Related Questions