'How to merge two objects and keep count
I am building a Rails 5.2 app. In this app I am working with statistics.
I generate two objects:
{
"total_project": {
"website": 1,
"google": 1,
"instagram": 1
}
}
And this:
{
"total_leads": {
"website": 1,
"google": 2,
"client_referral": 1
}
}
I need to merge these two objects into one single objects that increases the count. The desired result is:
{
"total_both": {
"website": 2,
"google": 3,
"instagram": 1,
"client_referral": 1
}
}
I tried this and it technically works, it merges the objects but the count is not updated:
@total_project = array_projects.group_by { |d| d[:entity_type] }.transform_values(&:count).symbolize_keys
@total_leads = array_leads.group_by { |d| d[:entity_type] }.transform_values(&:count).symbolize_keys
@total_sources = merged.merge **@total_project, **@total_leads
Please note that the attributes (sources) are dynamic from the database so I cannot hard code anything. The user can add their own sources.
Solution 1:[1]
@total_sources = @total_project.merge(@total_leads) do |key, ts_value, tp_value|
ts_value + tp_value
end
If there can be more than 2 sources, put everything in an array and do.
@total_sources = source_array.reduce do |accumulator, next_source|
accumulator.merge(next_source) { |key, v1, v2| v1 + v2 }
end
Solution 2:[2]
You may compute the desired result as follows.
arr = [{ "total_project": { "website": 1, "google": 1, "instagram": 1 } },
{ "total_leads": { "website": 1, "google": 2, "client_referral": 1 } }]
{ "total_both" => arr.flat_map(&:values)
.reduce { |h,g| h.merge(g) { |_,o,n| o+n } } }
#=> {"total_both"=>{:website=>2, :google=>3, :instagram=>1, :client_referral=>1}}
Note that
arr.flat_map(&:values)
#=> [{:website=>1, :google=>1, :instagram=>1},
# {:website=>1, :google=>2, :client_referral=>1}]
Had I used Array#map this would have been
arr.map(&:values)
#=> [[{:website=>1, :google=>1, :instagram=>1}],
# [{:website=>1, :google=>2, :client_referral=>1}]]
See Enumerable#flat_map, Enumerable#reduce and the form of Hash#merge that takes a block (here { |_,o,n| o+n }) which returns the values of keys that are present in both hashes being merged. See the doc for merge for definitions of the three block variables (here _, o and n). I have named the first block variable (holding the common key) _ to signal to the reader that it is not used in the block calculation (a common Ruby convention).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ben Garcia |
| Solution 2 |
