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"},
]
Creating an array of hashes You are allowed to create an array of hashes either by simply initializing array with hashes or by using array. push() to push hashes inside the array. Note: Both “Key” and :Key acts as a key in a hash in ruby.
All lists, mutable or not, hash by value. And you can use e.g. mutable ArrayList as hash keys.
Each key can only have one value. But the same value can occur more than once inside a Hash, while each key can occur only once.
The Ruby sort method works by comparing elements of a collection using their <=> operator (more about that in a second), using the quicksort algorithm. You can also pass it an optional block if you want to do some custom sorting. The block receives two parameters for you to specify how they should be compared.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With