2013-06-23 1 views
6

Я хотел бы group_by несколько ключей: заказы, idx, учетные записи и т. Д. Код ниже - это модифицированная версия Ruby on Rails - Hash of Arrays, group by and sum by column name. Может ли кто-нибудь рекомендовать способ группировки по нескольким ключам и суммировать несколько значений?Групповой массив хэшей несколькими ключами

Например, в приведенном ниже коде я группирую только «заказы». Я хотел бы группировать по заказам, idx и учетной записи.

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

против

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

Код:

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

Ожидаемый результат от ввода:

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"}, 
     ] 
+0

Что такое 'some'? – sawa

+0

@sawa исправлено, некоторые предполагали быть some_array. thanks – user2012677

+0

Каков ваш ожидаемый результат с учетом ввода 'some_array'? –

ответ

7

Я бы сделать это так:

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 

Вы можете группы по несколько ключей путем присоединения к ним с некоторым разделителем см arr.group_by {|hash| hash.values_at(*group_fields).join ":" }

И я полагаю, вам не нужно sum_field, потому что вообще все поля, которые не сгруппированных должны быть подведены итоги.

+0

отличное решение. Спасибо – user2012677