Ruby array of hash. group_by and modify in one line

16,042

Solution 1

array.group_by{|h| h[:type]}.each{|_, v| v.replace(v.map{|h| h[:name]})}
# => {"Meat"=>["one", "two"], "Fruit"=>["four"]}

Following steenslag's suggestion:

array.group_by{|h| h[:type]}.each{|_, v| v.map!{|h| h[:name]}}
# => {"Meat"=>["one", "two"], "Fruit"=>["four"]}

Solution 2

In a single iteration over initial array:

arry.inject(Hash.new([])) { |h, a| h[a[:type]] += [a[:name]]; h }

Solution 3

Using ActiveSuport's Hash#transform_values:

array.group_by{ |h| h[:type] }.transform_values{ |hs| hs.map{ |h| h[:name] } }
#=> {"Meat"=>["one", "two"], "Fruit"=>["four"]}

Solution 4

array = [{:type=>"Meat", :name=>"one"}, {:type=>"Meat", :name=>"two"}, {:type=>"Fruit", :name=>"four"}]
array.inject({}) {|memo, value| (memo[value[:type]] ||= []) << value[:name]; memo}

Solution 5

I would do as below :

hsh =[{:type=>"Meat", :name=>"one"}, {:type=>"Meat", :name=>"two"}, {:type=>"Fruit", :name=>"four"}]
p Hash[hsh.group_by{|h| h[:type] }.map{|k,v| [k,v.map{|h|h[:name]}]}]

# >> {"Meat"=>["one", "two"], "Fruit"=>["four"]}
Share:
16,042

Related videos on Youtube

jtomasrl
Author by

jtomasrl

Updated on June 17, 2022

Comments

  • jtomasrl
    jtomasrl about 2 years

    I have an array of hashes, something like

    [ {:type=>"Meat", :name=>"one"}, 
      {:type=>"Meat", :name=>"two"}, 
      {:type=>"Fruit", :name=>"four"} ]
    

    and I want to convert it to this

    { "Meat" => ["one", "two"], "Fruit" => ["Four"]}
    

    I tried group_by but then i got this

    { "Meat" => [{:type=>"Meat", :name=>"one"}, {:type=>"Meat", :name=>"two"}],
      "Fruit" => [{:type=>"Fruit", :name=>"four"}] }
    

    and then I can't modify it to leave just the name and not the full hash. I need to do this in one line because is for a grouped_options_for_select on a Rails form.

  • steenslag
    steenslag almost 11 years
    The last block can be written as {|_, v| v.map!{|h| h[:name]}}
  • sawa
    sawa almost 11 years
    @steenslag Thanks. I forgot about it.
  • Cary Swoveland
    Cary Swoveland almost 11 years
    ...or each_value..., and don't see why the !.
  • Cary Swoveland
    Cary Swoveland almost 11 years
    Nice! (But your preamble sounds like a drum roll. :-) )
  • Cary Swoveland
    Cary Swoveland almost 11 years
    .each_value {|v| v.map!{|h| h[:name]}} works, but I see ! is needed.
  • Cary Swoveland
    Cary Swoveland almost 11 years
    Your answer has given me greater insight into the coolness of inject. Thanks!
  • Matstar
    Matstar over 4 years
    transform_values is now part of Ruby itself (since 2.4, I think).