如何合并按值求和的哈希数组?

时间:2019-04-28 18:01:47

标签: ruby-on-rails ruby hash

我有一个哈希数组

[{:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>10},
 {:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>10},
 {:id=>2, :book=>{:title=>"title2", :desc=>"title2", :author=>"title2"}, :pages=>30}]

如何求和pages值,仅保留唯一键? 例如:

[{:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>20},
 {:id=>2, :book=>{:title=>"title2", :desc=>"title2", :author=>"title2"}, :pages=>30}]

2 个答案:

答案 0 :(得分:2)

让我们按ID分组,并将每个结果映射到一个结构,其中页面是该ID的所有页面的总和。

array.
  group_by { |item| item[:id] }.
  map do |id, items| 
    page_sum = items.sum { |i| i[:pages] }
    Hash[:id, id, :book, items.first[:book], :pages, page_sum] 
  end

答案 1 :(得分:1)

arr = [
  {:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>10},
  {:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>10},
  {:id=>2, :book=>{:title=>"title2", :desc=>"title2", :author=>"title2"}, :pages=>30}
]

arr.each_with_object({}) do |g,h|
  h.update(g[:id]=>g) { |_,o,n| o.merge(pages: o[:pages] + n[:pages]) }
end.values
  #=> [{:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>30},
  #    {:id=>2, :book=>{:title=>"title2", :desc=>"title2", :author=>"title2"}, :pages=>30}] 

请注意values的接收者等于

{1=>{:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>30},
 2=>{:id=>2, :book=>{:title=>"title2", :desc=>"title2", :author=>"title2"}, :pages=>30}} 

这使用Hash#update(也称为merge!)形式,并使用了该块

{ |_,o,n| o.merge(pages: o[:pages] + n[:pages]) }

确定合并的两个哈希中存在的键(块变量_)的值。有关块变量on的说明,请参阅文档。

Hash#updateEnumerable#group_by是处理此类问题时通常采用的两种方法。都可以使用。它们的效率大致相等,因此选择很大程度上是个人喜好之一。