I have an array of hashes, something like
[ {:type=>\"Meat\", :name=>\"one\"},
{:type=>\"Meat\", :name=>\"two\"},
{:type=>\"Fruit\", :n
array = [{:type=>"Meat", :name=>"one"}, {:type=>"Meat", :name=>"two"}, {:type=>"Fruit", :name=>"four"}]
array.inject({}) {|memo, value| (memo[value[:type]] ||= []) << value[:name]; memo}
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 }
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:
Hash of groups (first map), where|group_key, array] and return an Array of [group_key, new_array] (outer block),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.