Ruby array of hash. group_by and modify in one line

后端 未结 6 1404
不知归路
不知归路 2020-12-31 04:07

I have an array of hashes, something like

[ {:type=>\"Meat\", :name=>\"one\"}, 
  {:type=>\"Meat\", :name=>\"two\"}, 
  {:type=>\"Fruit\", :n         


        
相关标签:
6条回答
  • 2020-12-31 04:35
    array = [{:type=>"Meat", :name=>"one"}, {:type=>"Meat", :name=>"two"}, {:type=>"Fruit", :name=>"four"}]
    array.inject({}) {|memo, value| (memo[value[:type]] ||= []) << value[:name]; memo}
    
    0 讨论(0)
  • 2020-12-31 04:45
    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"]}
    
    0 讨论(0)
  • 2020-12-31 04:48

    In a single iteration over initial array:

    arry.inject(Hash.new([])) { |h, a| h[a[:type]] += [a[:name]]; h }
    
    0 讨论(0)
  • 2020-12-31 04:53

    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"]}
    
    0 讨论(0)
  • 2020-12-31 04:53

    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"]}
    
    0 讨论(0)
  • 2020-12-31 04:59

    @ArupRakshit answer, slightly modified (the function has been added for sake of clarity in the final example):

    def group(list, by, at)
      list.group_by { |h| h[by] }.map { |k,v| [ k , v.map {|h| h[at]} ] }.to_h
    end
    
    sample =[
      {:type=>"Meat",  :name=>"one",  :size=>"big"   },
      {:type=>"Meat",  :name=>"two",  :size=>"small" },
      {:type=>"Fruit", :name=>"four", :size=>"small" }
    ]
    
    group(sample, :type, :name) # => {"Meat"=>["one", "two"], "Fruit"=>["four"]}
    group(sample, :size, :name) # => {"big"=>["one"], "small"=>["two", "four"]}
    

    Please, notice that, although not mentioned in the question, you may want to preserve the original sample as it is. Some answers kept provision on this, others not as.

    After grouping (list.group_by {...}) the part that does the transformation (without modifying the original sample's values) is:

    .map { |k,v| [ k , v.map {|h| h[at]} ] }.to_h
    

    Some hints:

    1. iterating the pairs of the Hash of groups (first map), where
    2. for each iteration, we receive |group_key, array] and return an Array of [group_key, new_array] (outer block),
    3. and finally to_h transforms the Array of Arrays into the Hash (this [[gk1,arr1],[gk2,arr2]...] into this { gk1 => arr1, gk2 => arr2, ...})

    There is one missing step not explained at step (2) above. new_array is made by v.map {|h| h[at]}, which justs casts the value at of each original Hash (h) element of the array (so we move from Array of Hashes to an Array of elements).

    Hope that helps others to understand the example.

    0 讨论(0)
提交回复
热议问题