Group an array of hashes with multiple keys

I would like group_by several keys: orders, idx, account, etc. The code below is a modified version of Ruby on Rails - Hash of Arrays, grouping and sum in the column name . Can anyone recommend a way to group by multiple keys and summarize multiple values?

For example, in the code below, I group only β€œorders”. I would like to group by orders, idx and account.

group_hashes some_array, ["order","idx","account"] ["money","amt"] 

vs.

 group_hashes some_array, "order", "money","amt" 

code:

 some_array=[{"idx"=>"1234", "account"=>"abde", "amt"=>"2", "money"=>"4.00", "order"=>"00001"}, {"idx"=>"1235", "account"=>"abde", "amt"=>"2" , "money"=>"2.00", "order"=>"00001"}, {"idx"=>"1235", "account"=>"abde", "amt"=>"2" , "money"=>"3.00", "order"=>"00002"}] # => [{"idx"=>"1234", "account"=>"abde", "amt"=>"2", "money"=>"4.00", "order"=>"00001"}, {"idx"=>"1235", "account"=>"abde", "amt"=>"2", "money"=>"2.00", "order"=>"00001"}, {"idx"=>"1235", "account"... #group_hashes arr, "order", "money" def group_hashes arr, group_field, *sum_field arr.inject({}) do |res, h| (res[h[group_field]] ||= {}).merge!(h) do |key, oldval, newval| sum_field.include?(key) ? (oldval.to_f + newval.to_f).to_s : oldval # => "1234", "abde", "4.0", "6.0", "00001" end # => {"idx"=>"1234", "account"=>"abde", "amt"=>"2", "money"=>"4.00", "order"=>"00001"}, {"idx"=>"1234", "account"=>"abde", "amt"=>"4.0", "money"=>"6.0", "order"=>"00001"}, {"idx"=>"1235", "account"... res # => {"00001"=>{"idx"=>"1234", "account"=>"abde", "amt"=>"2", "money"=>"4.00", "order"=>"00001"}}, {"00001"=>{"idx"=>"1234", "account"=>"abde", "amt"=>"4.0", "money"=>"6.0", "order"=>"00001"}}, {"0... end.values # => [{"idx"=>"1234", "account"=>"abde", "amt"=>"4.0", "money"=>"6.0", "order"=>"00001"}, {"idx"=>"1235", "account"=>"abde", "amt"=>"2", "money"=>"3.00", "order"=>"00002"}] end # => nil group_hashes some_array, "order", "money","amt" # => [{"idx"=>"1234", "account"=>"abde", "amt"=>"4.0", "money"=>"6.0", "order"=>"00001"}, {"idx"=>"1235", "account"=>"abde", "amt"=>"2", "money"=>"3.00", "order"=>"00002"}] 

Expected input result:

 input =[ {"idx"=>"1234", "account"=>"abde", "amt"=>"2", "money"=>"4.00", "order"=>"00001"}, {"idx"=>"1234", "account"=>"abde", "amt"=>"2" ,"money"=>"2.00", "order"=>"00001"}, {"idx"=>"1235", "account"=>"abde", "amt"=>"2" , "money"=>"3.00", "order"=>"00002"}, {"idx"=>"1235", "account"=>"abde", "amt"=>"3", "money"=>"4.00", "order"=>"00002"}, {"idx"=>"1234", "account"=>"ddd", "amt"=>"2", "money"=>"4.00", "order"=>"00003"}, {"idx"=>"1234", "account"=>"ddd", "amt"=>"2", "money"=>"4.00", "order"=>"00003"} ] output =[ {"idx"=>"1234", "account"=>"abde", "amt"=>"4", "money"=>"6.00", "order"=>"00001"}, {"idx"=>"1235", "account"=>"abde", "amt"=>"5" , "money"=>"7.00", "order"=>"00002"}, {"idx"=>"1234", "account"=>"ddd", "amt"=>"4", "money"=>"8.00", "order"=>"00003"}, ] 
+6
source share
1 answer

I would do it like this:

 def group_hashes arr, group_fields arr.group_by {|hash| hash.values_at(*group_fields).join ":" }.values.map do |grouped| grouped.inject do |merged, n| merged.merge(n) do |key, v1, v2| group_fields.include?(key) ? v1 : (v1.to_f + v2.to_f).to_s end end end end 

You can group by several keys, attaching them to some separator, see arr.group_by {|hash| hash.values_at(*group_fields).join ":" } arr.group_by {|hash| hash.values_at(*group_fields).join ":" }

And I suppose you do not need sum_field , because, as a rule, all fields that are not grouped should be summed.

+7
source

Source: https://habr.com/ru/post/947949/


All Articles