简体   繁体   中英

Array of hashes to hash of hash

How can I transform an array of hashes response :

response = [
  {id: 1, name: 'foo', something: {}},
  {id: 2, name: 'bar', something: {}}
]

where the :id s are unique, to a hash of hashes transformed with values as the elements of response and the key as the corresponding :id value turned into a string as follows?

transformed = {
  '1' => {id: 1, name: 'foo', something: {}},
  '2' => {id: 2, name: 'bar', something: {}}
}

Since ruby 2.4.0 you can use native Hash#transform_values method:

response
.group_by{|h| h[:id]}
.transform_keys(&:to_s)
.transform_values(&:first)
# => {
#      "1"=>{:id=>1, :name=>"foo", :something=>{}},
#      "2"=>{:id=>2, :name=>"bar", :something=>{}}
#    }

other options

response.map{ |i| [i[:id].to_s, i] }.to_h
#=> {"1"=>{:id=>1, :name=>"foo", :something=>{}}, "2"=>{:id=>2, :name=>"bar", :something=>{}}}

Hash[response.map{ |i| [i[:id].to_s, i] }]
#=> {"1"=>{:id=>1, :name=>"foo", :something=>{}}, "2"=>{:id=>2, :name=>"bar", :something=>{}}

response.inject({}) { |h, i| h[i[:id].to_s] = i; h }
#=> {"1"=>{:id=>1, :name=>"foo", :something=>{}}, "2"=>{:id=>2, :name=>"bar", :something=>{}}}

@Stefan's solution

response.each.with_object({}) { |i, h| h[i[:id].to_s] = i }
#=> {"1"=>{:id=>1, :name=>"foo", :something=>{}}, "2"=>{:id=>2, :name=>"bar", :something=>{}}}

@engineersmnky's solution

response.inject({}) {|h,i| h.merge({i[:id].to_s => i})} 
#=> {"1"=>{:id=>1, :name=>"foo", :something=>{}}, "2"=>{:id=>2, :name=>"bar", :something=>{}}}
response = [{ id: 1, name: 'foo', something: {} },{ id: 2, name: 'bar', something: { } }]    
hash = Hash.new    
response.each {|a| hash[a[:id].to_s] = a }
puts hash

If you will have the id as key in resulting hash, there is no need to keep it in the value again. See my solution using each_with_object (with id removed from value):

input
 => [{:id=>1, :name=>"foo", :something=>{}},
     {:id=>2, :name=>"bar", :something=>{}}]

input.each_with_object({}) do |hash, out|
  out[hash.delete(:id).to_s] = hash
end
 => {"1"=>{:name=>"foo", :something=>{}},
     "2"=>{:name=>"bar", :something=>{}}}

Note: It will modify the input array permanently.

However, to have the exact output as mentioned in the question, do:

input.each_with_object({}) do |hash, out|
  out[hash[:id].to_s] = hash
end
 => {"1"=>{:id=>1, :name=>"foo", :something=>{}},
     "2"=>{:id=>2, :name=>"bar", :something=>{}}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM