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.
CodePudding user response:
@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
CodePudding user response:
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).