如何合并两个对象并保持计数

How to merge two objects and keep count

我正在构建一个 Rails 5.2 应用程序。 在这个应用程序中,我正在处理统计数据。

我生成了两个对象:

{
    "total_project": {
        "website": 1,
        "google": 1,
        "instagram": 1
    }
}

还有这个:

{
    "total_leads": {
        "website": 1,
        "google": 2,
        "client_referral": 1
    }
}

我需要将这两个对象合并为一个对象以增加计数。期望的结果是:

{
    "total_both": {
        "website": 2,
        "google": 3,
        "instagram": 1,
        "client_referral": 1
    }
}

我试过了,技术上可行,它合并了对象,但计数没有更新:

@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

请注意,属性(来源)是数据库中的动态属性,因此我无法对任何内容进行硬编码。用户可以添加自己的来源。

@total_sources = @total_project.merge(@total_leads) do |key, ts_value, tp_value|
  ts_value + tp_value
end

如果源可以超过 2 个,则将所有内容放入一个数组中并执行。

@total_sources = source_array.reduce do |accumulator, next_source|
  accumulator.merge(next_source) { |key, v1, v2| v1 + v2 }
end

您可以按如下方式计算所需的结果。

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}}

注意

arr.flat_map(&:values)
  #=> [{:website=>1, :google=>1, :instagram=>1},
  #    {:website=>1, :google=>2, :client_referral=>1}]

如果我使用 Array#map 这会是

arr.map(&:values)
  #=> [[{:website=>1, :google=>1, :instagram=>1}],
  #    [{:website=>1, :google=>2, :client_referral=>1}]]

请参阅 Enumerable#flat_map, Enumerable#reduce and the form of Hash#merge,它采用一个块(此处为 { |_,o,n| o+n }),其中 returns 合并两个散列中存在的键的值。请参阅 merge 的文档以了解三个块变量的定义(此处为 _on)。我已将第一个块变量(持有公共键)命名为 _ 以向 reader 发出信号,表明它未在块计算中使用(常见的 Ruby 约定)。