Ruby array of hash. group_by and modify in one line

瘦欲@ 提交于 2019-11-30 08:41:54
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"]}

In a single iteration over initial array:

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

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

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

@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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!