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
Validation for Non-Negative Integers and Decimal Values
Ruby Style: How to Check Whether a Nested Hash Element Exists
Optional Argument After Splat Argument
How to Make a Http Request Using Ruby on Rails
The 'Json' Native Gem Requires Installed Build Tools
How to Set Tls Context Options in Ruby (Like Openssl::Ssl::Ssl_Op_No_Sslv2)
What Are All the Common Ways to Read a File in Ruby
What's the Difference Between Uri.Escape and Cgi.Escape
How to Create Multiple Submit Buttons For the Same Form in Rails
No Increment Operator (++) in Ruby
How to Install Sqlite3 For Ruby on Windows
Difference Between Collection Route and Member Route in Ruby on Rails
What Are the Ruby Gotchas a Newbie Should Be Warned About
Limitations in Running Ruby/Rails on Windows