簡體   English   中英

合並包含相同鍵和值對的哈希

[英]Merge hashes containing same key & value pair

arr1 = [
  {entity_type: "Mac", entity_ids: [3], cascade_id: 2, location_id: 1},
  {entity_type: "Mac", entity_ids: [2], cascade_id: 2, location_id: 1},
  {entity_type: "Mac", entity_ids: [9], cascade_id: 4, location_id: 1},
  {entity_type: "Mac", entity_ids: [10], cascade_id: 4, location_id: 1}
]

這是我在一些邏輯迭代之后得到的數據的一部分。 這個例子的我想要的輸出是

[{entity_type: "Mac", entity_ids: [3,2], cascade_id: 2, location_id: 1}, {entity_type: "Mac", entity_ids: [9,10], cascade_id: 4, location_id: 1}]

我想知道如果合並哈希,如果它的一個或兩個鍵值對相同​​,則將其他鍵的值合並到數組中。

- >這是另一個例子

arr2 = [
  {entity_type: "Sub", entity_ids: [7], mac_id: 5, cascade_id: 1, location_id: 1},
  {entity_type: "Sub", entity_ids: [10], mac_id: 5, cascade_id: 1, location_id: 1},
  {entity_type: "Sub", entity_ids: [4], mac_id: 2, cascade_id: 1, location_id: 1},
  {entity_type: "Sub", entity_ids: [11], mac_id: 7, cascade_id: 2, location_id: 2}
]

此實例的所需輸出是

[{entity_type: "Sub", entity_ids: [7, 10], mac_id: 5, cascade_id: 1, location_id: 1}, {entity_type: "Sub", entity_ids: [4], mac_id: 2, cascade_id: 1, location_id: 1}, {entity_type: "Sub", entity_ids: [11], mac_id: 7, cascade_id: 2, location_id: 2}]

這將有效:

  def combine(collection)
    return [] if collection.empty?
    grouping_key = collection.first.keys - [:entity_ids]

    grouped_collection = collection.group_by do |element|
      grouping_key.map { |key| [key, element[key]] }.to_h
    end

    grouped_collection.map do |key, elements|
      key.merge(entity_ids: elements.map { |e| e[:entity_ids] }.flatten.uniq)
    end
  end

這是發生了什么:

首先,我們通過對第一個元素的鍵進行采樣並刪除:entity_ids來確定集合的“分組鍵”。 組合的所有其他鍵組成組合所依賴的分組鍵。

Enumerable#group_by方法迭代一個集合,並按我們剛剛構造的分組鍵對其進行分組。

然后,我們遍歷分組集合並合並新的entity_ids屬性,該屬性由來自每個組的組合實體ID組成。

您可以按如下方式計算所需的結果。

def doit(arr)
  arr.each_with_object({}) do |g,h|
    h.update(g.reject { |k,_| k==:entity_ids }=>g) do |_,o,n|
      o.merge(entity_ids: o[:entity_ids] + n[:entity_ids])
    end
  end.values
end

doit(arr1)
  #=> [{:entity_type=>"Mac", :entity_ids=>[3, 2], :cascade_id=>2, :location_id=>1},
  #    {:entity_type=>"Mac", :entity_ids=>[9, 10], :cascade_id=>4, :location_id=>1}]
doit(arr2)
  #=> [{:entity_type=>"Sub", :entity_ids=>[7, 10], :mac_id=>5, :cascade_id=>1,
  #     :location_id=>1},
  #    {:entity_type=>"Sub", :entity_ids=>[4], :mac_id=>2, :cascade_id=>1,
  #     :location_id=>1},
  #    {:entity_type=>"Sub", :entity_ids=>[11], :mac_id=>7, :cascade_id=>2,
  #     :location_id=>2}]

這使用Hash#update (aka merge! )的形式,它使用塊來確定合並的兩個哈希中存在的鍵的值。 有關塊變量kon的解釋,請參閱doc。

如果doit的參數是arr1 ,則步驟如下。

arr = arr1
e =  arr.each_with_object({})
  #=> #<Enumerator: [{:entity_type=>"Mac", :entity_ids=>[3], :cascade_id=>2,
  #                   :location_id=>1},
  #                  {:entity_type=>"Mac", :entity_ids=>[2], :cascade_id=>2,
  #                   :location_id=>1},
  #                  {:entity_type=>"Mac", :entity_ids=>[9], :cascade_id=>4,
  #                   :location_id=>1},
  #                  {:entity_type=>"Mac", :entity_ids=>[10], :cascade_id=>4,
  #                  :location_id=>1}
  #                 ]:each_with_object({})>

枚舉器的第一個元素傳遞給塊,值分配給塊變量。

g, h = e.next
  #=> [{:entity_type=>"Mac", :entity_ids=>[3], :cascade_id=>2, :location_id=>1}, {}]
g #=> {:entity_type=>"Mac", :entity_ids=>[3], :cascade_id=>2, :location_id=>1}
h #=> {}

計算要與h合並的哈希的(唯一)鍵。

a = g.reject { |k,_| k==:entity_ids }
  #=> {:entity_type=>"Mac", :cascade_id=>2, :location_id=>1}

執行更新操作。

h.update(a=>g)
  #=> {{:entity_type=>"Mac", :cascade_id=>2, :location_id=>1}=>
  #    {:entity_type=>"Mac", :entity_ids=>[3], :cascade_id=>2, :location_id=>1}}

這是h的新值。 因為h (空的)沒有鑰匙

{:entity_type=>"Mac", :cascade_id=>2, :location_id=>1}

該塊未用於確定合並哈希中此鍵的值。

現在生成枚舉器e的下一個值,將其傳遞給塊,為塊變量賦值並執行塊計算。

g, h = e.next
  #=> [{:entity_type=>"Mac", :entity_ids=>[2], :cascade_id=>2, :location_id=>1},
  #    {{:entity_type=>"Mac", :cascade_id=>2, :location_id=>1}=>
  #     {:entity_type=>"Mac", :entity_ids=>[3], :cascade_id=>2, :location_id=>1}}]
g #=> {:entity_type=>"Mac", :entity_ids=>[2], :cascade_id=>2, :location_id=>1}
h #=> {{:entity_type=>"Mac", :cascade_id=>2, :location_id=>1}=>
  #    {:entity_type=>"Mac", :entity_ids=>[3, 2], :cascade_id=>2, :location_id=>1}}
a = g.reject { |k,_| k==:entity_ids }
  #=> {:entity_type=>"Mac", :cascade_id=>2, :location_id=>1}
h.update(a=>g) do |_,o,n|
  puts "_=#{_}, o=#{o}, n=#{n}"
  o.merge(entity_ids: o[:entity_ids] + n[:entity_ids])
end
  #=> {{:entity_type=>"Mac", :cascade_id=>2, :location_id=>1}=>
  #    {:entity_type=>"Mac", :entity_ids=>[3, 2], :cascade_id=>2, :location_id=>1}}

這是h的新值。 由於gh都具有密鑰a該塊以獲得合並散列中的該密鑰的值(新h )。 打印該塊變量的值。

_={:entity_type=>"Mac", :cascade_id=>2, :location_id=>1},
o={:entity_type=>"Mac", :entity_ids=>[3], :cascade_id=>2, :location_id=>1},
n={:entity_type=>"Mac", :entity_ids=>[2], :cascade_id=>2, :location_id=>1}

h[:entity_ids]因此被替換為

o[:entity_ids] + o[:entity_ids]
  #=> [3] + [2] => [3, 2]

e的兩個剩余元素的計算是相似的,此時

h #=> {{ :entity_type=>"Mac", :cascade_id=>2, :location_id=>1 }=>
  #      { :entity_type=>"Mac", :entity_ids=>[3, 2], :cascade_id=>2, :location_id=>1 },
  #    { :entity_type=>"Mac", :cascade_id=>4, :location_id=>1 }=>
  #      { :entity_type=>"Mac", :entity_ids=>[9, 10], :cascade_id=>4, :location_id=>1 }}

最后一步是返回此哈希的值。

h.values
  #=> <as shown above>

請注意,某些塊變量是下划線( _ )。 雖然它們是有效的局部變量,但它們通常用於表示它們不用於塊計算中。 另一種約定是使未使用的塊變量以下划線開頭,例如_key

你的問題有兩個獨立的挑戰。

  1. 合並哈希。
  2. 僅在其他值不匹配時合並。

問題1:

要在合並時獲得任何自定義行為,可以將塊傳遞給merge方法。 在您的情況下,您想要組合實體ID的數組。 此塊采用鍵和左右值。 在scenerio中,如果key ==:entity_ids,則要組合數組。

one_entity.merge(other_entity){ |key, left, right|
  key== :entity_ids ? left + right : left
}

問題2:

要根據實體是否具有不同的屬性或相同來合並實體,我使用的是group_by。 這將給我一個哈希組合實體,可以合並到我可以映射和合並的數組。

actual.group_by {|x| [x[:entity_type], x[:mac_id], x[:location_id]]}

結合這兩個將給我整個解決方案的工作。 如果需要,可以在group_by塊中添加更多屬性。

actual.group_by {|x| [x[:entity_type], x[:mac_id], x[:location_id]]}
      .map{|_, entities| entities.reduce({}) { |result, entity|
        result.merge(entity){|key, left, right|
          key== :entity_ids ? left + right : left
        }
      }
}

暫無
暫無

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

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