Group Hashes by Keys and Sum the Values

Group hashes by keys and sum the values

ar = [{"Vegetable"=>10}, {"Vegetable"=>5}, {"Dry Goods"=>3}, {"Dry Goods"=>2}]
p ar.inject{|memo, el| memo.merge( el ){|k, old_v, new_v| old_v + new_v}}
#=> {"Vegetable"=>15, "Dry Goods"=>5}

Hash.merge with a block runs the block when it finds a duplicate; inject without a initial memo treats the first element of the array as memo, which is fine here.

i want to make a group Hash by keys and add values

I'd use the each_with_object method.
(key, value) here is a deconstruction of each key/value pair like 93=>1, hash is an intermediate object to store the result.

data.each_with_object({}) do |(key, value), hash|
result_key =
case key
when 10..19 then 1
when 20..29 then 2
when 90..99 then 9
end
next if result_key.nil?
hash[result_key] ||= 0
hash[result_key] += value
end

For the provided input I got {9=>2, 2=>7856, 1=>267}

UPD

A shorter solution suggested by Holger Just and Stefan in the comments below.

data.each_with_object(Hash.new(0)) do |(key, value), hash|
hash[key / 10] += value
end

With Hash.new(0) the initial object will be a hash with the default value 0

> hash = Hash.new(0)
=> {}
> hash[1]
=> 0

How to group by a hash key with sum and average

data = {"2020-08-01"=>139.008, "2020-08-02"=>125.170, "2020-08-03"=>125.712,
"2020-08-04"=>125.704, "2020-08-05"=>125.968}

require 'date'

data.each_with_object({}) do |(date_str,v),h|
(h[Date.strptime(date_str, '%Y-%m-%d').cweek.to_s] ||= []) << v
end.transform_values do |arr|
tot = arr.sum
{ "sum"=>tot, "avg"=> tot.fdiv(arr.size).round(3) }
end
#=> {"31"=>{"sum"=>264.178, "avg"=>132.089},
# "32"=>{"sum"=>377.384, "avg"=>125.795}}

The first step is as follows:

data.each_with_object({}) do |(date_str,v),h|      
(h[Date.strptime(date_str, '%Y-%m-%d').cweek.to_s] ||= []) << v
end
#=> {"31"=>[139.008, 125.17], "32"=>[125.712, 125.704, 125.968]}

See Date::strptime and Date#cweek.

It is then a simple matter to convert the arrays to hashes with keys "sum" and "avg". See Hash#transform_values.

It is even easier to compute the values by month, as no Date methods are needed:

data.each_with_object({}) do |(date_str,v),h|      
(h[date_str[5,2]] ||= []) << v
end.transform_values do |arr|
tot = arr.sum
{ "sum"=>tot, "avg"=> tot.fdiv(arr.size).round(3) }
end
#=> {"08"=>{"sum"=>641.562, "avg"=>128.312}}

How do I group and add values from nested hashes and arrays with same key?

Whatever you expect can be achieved as below,

student_data.values.map do |z|
z.group_by { |x| x[:student_id] }.transform_values do |v|
{
points: v.map { |x| x[:points] }.sum, # sum of points
grade: (v.map { |x| x[:grade] }.sum/v.count.to_f).round(2) # average of grades
}
end
end

As exact expected output format is not specified, obtained in following way,

=> [
{"ST4"=>{:points=>35, :grade=>4.67}},
{"ST1"=>{:points=>85, :grade=>3.0}},
{"ST2"=>{:points=>75, :grade=>3.0}},
{"ST3"=>{:points=>55, :grade=>3.5}}
]

Sum values in array of hash if they have the same value

This seems work

array.group_by { |item| [item[:loading], item[:avg]] }.values.flat_map { |items| items.first.merge(total: items.sum { |h| h[:total] }) }
=> [{:loading=>10, :avg=>15, :total=>25}, {:loading=>20, :avg=>20, :total=>120}, {:loading=>30, :avg=>25, :total=>55}, {:loading=>10, :avg=>20, :total=>46}]

Rails sum values in an array of hashes

You could use each_with_object with a Hash and a default value:

array = [
{loading: 10, avg: 15, total: 25 },
{loading: 20, avg: 20, total: 40 },
{loading: 30, avg: 25, total: 55 }
]

sum = Hash.new(0)

array.each_with_object(sum) do |hash, sum|
hash.each { |key, value| sum[key] += value }
end
# => {:loading=>60, :avg=>60, :total=>120}

It will work with any number of keys, and won't complain if a key isn't present in all the hashes.


BTW, you can replace

array.map { |h| h[:loading] }.sum

with

array.sum { |h| h[:loading] }

Group by and sum array of hashes in javascript

Using an ES6 Map and reduce:

const responseData = [{deviceType: "Smartphone", deviceCount: 14},{deviceType: "Tablet", deviceCount: 11},{deviceType: "Notebook", deviceCount: 3},{deviceType: "Desktop", deviceCount: 2},{deviceType: "Smartphone", deviceCount: 1},{deviceType: "Tablet", deviceCount: 10},{deviceType: "Notebook", deviceCount: 30},{deviceType: "Desktop", deviceCount: 20}];
const result = Array.from( responseData.reduce( (acc, o) => (acc.get(o.deviceType).deviceCount += o.deviceCount, acc), new Map(responseData.map( ({deviceType}) => [deviceType, {deviceType, deviceCount: 0} ] )) ).values());
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

how to sum values inside array hash with same key in ruby

[{"nationalvoice"=>"5"}, {"nationalvoice"=>"1"}]
.group_by{|h| h.keys.first}.values
.map{|a| {
a.first.keys.first =>
a.inject(0){|sum, h| sum + h.values.first.to_i}.to_s
}}
# => [{"nationalvoice"=>"6"}]


Related Topics



Leave a reply



Submit