Sachin srinivasan
Sachin srinivasan

Reputation: 828

How to convert nested array to hash or JSON with values as array

I have this nested array

array = [["Colorado", "Adams County"], ["Colorado", "Jefferson County"], ["California", "Amador"], ["California", "Tulare"]]

I am expecting this

{"Colorado" => ["Adams County", "Jefferson County"], "California" => ["Amador", "Tulare"]}

I tried these:

array.to_h
#=> {"Colorado"=>"Jefferson County", "California"=>"Tulare"}

b = Hash.new
array.uniq.map{|k,v| b[k] = v}
#=> {"Colorado"=>"Jefferson County", "California"=>"Tulare"}

array.uniq.map{|k,v| b[k] << v}
#=> Error

array.map{|k,v| b[k] = [v]}
#=> {"Colorado"=>["Jefferson CountyAdams CountyJefferson CountyAdams County"], "California"=>["TulareAmadorTulareAmador"]}`

How can I get the values as an array?

Upvotes: 2

Views: 816

Answers (3)

Simple Lime
Simple Lime

Reputation: 11070

You can first call group_by and then transform_values (Ruby 2.4+):

hash = array.group_by(&:first)
# => {"Colorado"=>[["Colorado", "Adams County"], ["Colorado", "Jefferson County"]], "California"=>[["California", "Amador"], ["California", "Tulare"]]}
hash.transform_values! { |value_list| value_list.map(&:last) }
# => {"Colorado"=>["Adams County", "Jefferson County"], "California"=>["Amador", "Tulare"]}

If your ruby doesn't have transform_values, you can just map!:

hash = array.group_by(&:first)
hash.each_value do |value_list|
  value_list.map!(&:last)
end
# => {"Colorado"=>["Adams County", "Jefferson County"], "California"=>["Amador", "Tulare"]}

Upvotes: 4

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

[["Colorado", "Adams County"], ["Colorado", "Jefferson County"],
 ["California", "Amador"], ["California", "Tulare"]].
   each_with_object(Hash.new { |h, k| h[k] = [] }) do |(k, v), h|
     h[k] << v
   end
#⇒ {
#  "California" => [
#    [0] "Amador",
#    [1] "Tulare"
#  ],
#    "Colorado" => [
#    [0] "Adams County",
#    [1] "Jefferson County"
#  ]
# }

Or, for Ruby 2.4+:

[["Colorado", "Adams County"], ["Colorado", "Jefferson County"], 
 ["California", "Amador"], ["California", "Tulare"]].
   group_by(&:shift).transform_values(&:flatten)

Upvotes: 1

mwp
mwp

Reputation: 8467

It looks like you want Enumerable#group_by to regroup the array of arrays by the first element.

array
  .group_by { |k, _| k }
  .each_value { |a| a.map! { |_, v| v } } # => {"Colorado"=>["Adams County", "Jefferson County"], "California"=>["Amador", "Tulare"]}

Upvotes: 1

Related Questions