質問

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

For example, in the below code, I group only on "orders". I would like to group on 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 output from input:

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"},
        ] 
役に立ちましたか?

解決

I would do it this way:

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 multiple keys by joining them with some delimiter, see arr.group_by {|hash| hash.values_at(*group_fields).join ":" }

And I suppose, you don't need sum_field, because generally all fields that aren't grouped should be summed up.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top