簡體   English   中英

Ruby根據一個哈希值在一個數組中組合哈希

[英]Ruby combining hashes in an array based on one hash value

我有一系列的哈希,看起來像:

[
  {"id"=>1, "name"=>"Batman", "net_worth"=>100, "vehicles"=>2},
  {"id"=>1, "name"=>"Batman", "net_worth"=>100, "vehicles"=>2},
  {"id"=>2, "name"=>"Superman", "net_worth"=>100, "vehicles"=>2},
  {"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100, "vehicles"=>2}
]

我想在保留ID的基礎上結合基於id的哈希值,保留名稱,並對net_worth和Vehicle值求和。

因此,最終數組如下所示:

[
  {"id"=>1, "name"=>"Batman", "net_worth"=>200, "vehicles"=>4},
  {"id"=>2, "name"=>"Superman", "net_worth"=>100, "vehicles"=>2},
  {"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100, "vehicles"=>2}
]

這是您的問題的解決方案。 如您所見,您應該按ID和名稱對行進行分組,然后計算其他值的總和並生成結果:

rows = [
    {"id"=>1, "name"=>"Batman", "net_worth"=>100, "vehicles"=>2},
    {"id"=>1, "name"=>"Batman", "net_worth"=>100, "vehicles"=>2},
    {"id"=>2, "name"=>"Superman", "net_worth"=>100, "vehicles"=>2},
    {"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100, "vehicles"=>2}
]

groups = rows.group_by {|row| [row['id'], row['name']] }

result = groups.map do |key, values|
  id, name = *key

  total_net_worth = values.reduce(0) {|sum, value| sum + value['net_worth'] }
  total_vehicles = values.reduce(0) {|sum, value| sum + value['vehicles'] }

  { "id" => id, "name" => name, "net_worth" => total_net_worth, "vehicles" => total_vehicles }
end

p result

這是兩種可與任意數量的鍵-值對一起使用且不依賴於鍵名的方法(當然, "id""name"除外,它們是規范的一部分)。

使用update

這是一種使用Hash#update (也稱為merge! )形式的方法,該方法采用一個塊來確定兩個哈希中都存在的鍵的值:

arr = [
  {"id"=>1, "name"=>"Batman",      "net_worth"=>100, "vehicles"=>2}, 
  {"id"=>1, "name"=>"Batman",      "net_worth"=>100, "vehicles"=>2}, 
  {"id"=>2, "name"=>"Superman",    "net_worth"=>100, "vehicles"=>2},
  {"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100, "vehicles"=>2}
]   

arr.each_with_object({}) { |g,h|
  h.update(g["id"]=>g.dup) { |_,oh,nh|
    oh.update(nh) { |k,ov,nv|
      (['id','name'].include?(k)) ? ov : ov+nv } } }.values
  #=> [{"id"=>1, "name"=>"Batman", "net_worth"=>200, "vehicles"=>4}, 
  #    {"id"=>2, "name"=>"Superman", "net_worth"=>100, "vehicles"=>2},
  #    {"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100,"vehicles"=>2}]   

使用group_by

也可以使用Enumerable#group_by來完成,就像@maxd一樣,但是以下是更緊湊和更通用的實現:

arr.map(&:dup).
    group_by { |row| row['id'] }.
    map { |_,arr|
      arr.reduce { |h, g|
        (g.keys - ['id','name']).each { |k| h[k] += g[k] }; h } }

  #=> [{"id"=>1, "name"=>"Batman", "net_worth"=>200, "vehicles"=>4}, 
  #    {"id"=>2, "name"=>"Superman", "net_worth"=>100, "vehicles"=>2},
  #    {"id"=>3, "name"=>"Wonderwoman", "net_worth"=>100,"vehicles"=>2}]   

arr.map(&:dup)是為了避免對arr進行變異。 我使用了不帶參數的reduce來避免復制具有鍵"id""name"的鍵值對。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM