2

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?

2
  • What is the difference between array and c? (What is array in the first place?) What is b? Commented Nov 27, 2017 at 9:43
  • sorry i was working something on console, i have edited variables now. it should be more clear Commented Nov 27, 2017 at 9:52

3 Answers 3

4

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"]}
Sign up to request clarification or add additional context in comments.

1 Comment

How about each_value?
1

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"]}

Comments

1
[["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)

4 Comments

Oh, I like the shift one. But how about array.group_by(&:shift).each_value(&:flatten!)? Works in earlier Ruby versions as well and is a bit shorter.
cool.. .each_value is also great. Just wondering, is it possible to sort array value with .sort along with flatten ?
Speaking of sorting... is the output shown above really what you got from that code? Did it really make "California" come before "Colorado"? Doesn't that violate the "key insertion order"?
@StefanPochmann it’s how pry outputs the result: it sorts hashes.

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.