簡體   English   中英

如何將哈希與哈希數組中的不同鍵/值對合並? Ruby

[英]How to merge hashes with different key/value pairs in array of hashes? Ruby

這是哈希數組:

array = [
  {:ID=>"aaa", :step2=>80},
  {:ID=>"aaa", :step1=>160},
  {:ID=>"aaa", :step3=>70},
  {:ID=>"bbb", :step1=>80}
]

我正在嘗試合並具有相同:ID的散列並插入 value = 0 的缺失鍵,如下所示:

array = [
  {:ID=>"aaa", :step1 => 160, :step2 => 80, :step3 => 70},
  {:ID=>"bbb", :step1 => 80, :step2 => 0, :step3 => 0}
]

這是我的解決方案:

array = [
  {ID: "aaa", step2: 80},
  {ID: "aaa", step1: 160},
  {ID: "aaa", step3: 70},
  {ID: "bbb", step1: 80}
]

def group_by_id(hashes)
  # gather all IDs
  ids = hashes.map { |h| h[:ID] }.uniq
  keys = hashes.reduce([]) { |keys, hash| keys |= hash.keys }

  default_hash = {}
  keys.each do |key|
    default_hash[key] = 0
  end

  ids.map do |id|
    hashes.select { |hash| hash[:ID] == id }
          .reduce(default_hash) { |reduced, hash| reduced.merge(hash) }
  end
end

desired_array = [
  {ID: "aaa", step1: 160, step2: 80, step3: 70},
  {ID: "bbb", step1: 80, step2: 0, step3: 0}
]

output = group_by_id(array)
puts output
puts desired_array == output

#each_with_object方法在這里可能很有用。 在這種情況下,我們將傳遞一個 hash h ,它會針對array中的每個元素進行更新。 然后由#each_with_object方法返回 hash。

注意: ||=如果左側為nilfalse ,則將右側分配給左側。

array.each_with_object({}) { |x, h| (h[x[:ID]] ||= {}).update(x) }

產量:

{"aaa"=>{"ID"=>"aaa", "step3"=>70, "step1"=>160, "step2"=>80}, 
 "bbb"=>{"ID"=>"bbb", "step1"=>80}}

然后我們只需要使用#values來獲取我們想要的數據。

array
  .each_with_object({}) { |x, h| (h[x[:ID]] ||= {}).update(x) }
  .values

產量:

[{"ID"=>"aaa", "step3"=>70, "step1"=>160, "step2"=>80}, 
 {"ID"=>"bbb", "step1"=>80}]

但是您希望缺少用0填充的鍵。 為此,我們必須知道所有的鍵是什么,然后我們可以再次使用#each_with_object

grouped = array
           .each_with_object({}) { |x, h| (h[x[:ID]] ||= {}).update(x) }
           .values

all_keys = grouped.map(&:keys).flatten.uniq

grouped.map! { |h| all_keys.each_with_object(h) { |k, _h| _h[k] ||= 0 } }

現在grouped為:

[{"ID"=>"aaa", "step2"=>80, "step1"=>160, "step3"=>70}, 
 {"ID"=>"bbb", "step1"=>80, "step2"=>0, "step3"=>0}]

這可以分四個步驟完成。

array = [{:ID=>"aaa", :step2=>80}, {:ID=>"aaa", :step1=>160},
         {:ID=>"aaa", :step3=>70}, {:ID=>"bbb", :step1=>80}]

在添加缺少的零值鍵之前,構造一個 hash,其值是包含要返回的所需數組的哈希值

h = array.each_with_object({}) do |g,h|
  h.update(g[:ID]=>g) { |_,o,n| o.merge(n)}
end
  #=> {"aaa"=>{:ID=>"aaa", :step2=>80, :step1=>160, :step3=>70},
  #    "bbb"=>{:ID=>"bbb", :step1=>80, :step4=>40}}

請參閱Hash#update (又名merge )的形式,它采用一個塊,該塊返回正在合並的兩個哈希中存在的鍵的值。 這里的塊是:

{ |_,o,n| o.merge(n)}

塊變量_保存公共鍵的值。 為該變量使用下划線的主要原因是向讀者表明該鍵未在塊計算中使用。 有關塊變量on的定義,請參見文檔。

構造出現在數組所有元素中的所有唯一stepX鍵的array

step_keys = array.flat_map { |g| g.keys }.uniq - [:ID]
  #=> [:step2, :step1, :step3, :step4]

請參閱Enumerable#flat_map

添加缺少的鍵

step_keys.each_with_object(h) { |k,g| g.each_value { |v| v[k] ||= 0 } }​
  #=> {"aaa"=>{:ID=>"aaa", :step2=>80, :step1=>160, :step3=>70, :step4=>0},
  #    "bbb"=>{:ID=>"bbb", :step1=>80, :step4=>40, :step2=>0, :step3=>0}}

現在

h #=> {"aaa"=>{:ID=>"aaa", :step2=>80, :step1=>160, :step3=>70, :step4=>0},
  #    "bbb"=>{:ID=>"bbb", :step1=>80, :step4=>40, :step2=>0, :step3=>0}}

返回一個包含h值的數組

h.values
  #=> [{:ID=>"aaa", :step2=>80, :step1=>160, :step3=>70, :step4=>0},
  #    {:ID=>"bbb", :step1=>80, :step4=>40, :step2=>0, :step3=>0}]

這四個語句可以組合成一個語句,但我不建議這樣做,因為可讀性會受到影響並且代碼會更難測試。


根據要求,可以編寫:

a = array.each_with_object({}) do |g,h|
  h.update(g[:ID]=>Hash.new(0).merge(g)) { |_,o,n| o.merge(n) }
end.values
  #=> [{:ID=>"aaa", :step2=>80, :step1=>160, :step3=>70},
  #    {:ID=>"bbb", :step1=>80, :step4=>40}]

這將返回與以前相同的數組,但現在:

a[0][:step4]
  #=> 0

即使 hash a[0]沒有鍵:step4

請參閱Hash::new的形式,它接受一個參數但現在阻塞,參數是默認值 當定義了 hash

h = Hash.new(0)

然后(可能在將鍵添加到h之后),當h沒有鍵k時, h[k]返回默認值

在確定此變體是否滿足要求時,有明顯的考慮因素需要權衡。

暫無
暫無

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

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