簡體   English   中英

從 python 中的兩個字典列表中合並具有相同鍵的字典

[英]Merge dictionaries with same key from two lists of dicts in python

我有兩本字典,如下所示。 兩個詞典都有一個詞典列表作為與其properties鍵關聯的值; 這些列表中的每個字典都有一個id鍵。 我希望將我的兩個詞典合並為一個,這樣生成的詞典中的properties列表每個id只有一個詞典。

{
   "name":"harry",
   "properties":[
      {
         "id":"N3",
         "status":"OPEN",
         "type":"energetic"
      },
      {
         "id":"N5",
         "status":"OPEN",
         "type":"hot"
      }
   ]
}

和另一個列表:

{
   "name":"harry",
   "properties":[
      {
         "id":"N3",
         "type":"energetic",
         "language": "english"
      },
      {
         "id":"N6",
         "status":"OPEN",
         "type":"cool"
      }
   ]
}

我要實現的 output 是:

   "name":"harry",
   "properties":[
      {
         "id":"N3",
         "status":"OPEN",
         "type":"energetic",
         "language": "english"
      },
      {
         "id":"N5",
         "status":"OPEN",
         "type":"hot"
      },
      {
         "id":"N6",
         "status":"OPEN",
         "type":"cool"
      }
   ]
}

由於id: N3在兩個列表中都很常見,因此這兩個字典應該與所有字段合並。 到目前為止,我已經嘗試使用itertools

ds = [d1, d2]
d = {}
for k in d1.keys():
  d[k] = tuple(d[k] for d in ds)

有人可以幫忙解決這個問題嗎?

將這兩個對象視為各自列表中的元素可能會有所幫助。 也許您有其他具有不同name值的對象,例如可能來自 JSON 格式的 REST 請求。

然后你可以對nameid鍵進行左外連接

#!/usr/bin/env python

a = [
    {
        "name": "harry",
        "properties": [
            {
                "id":"N3",
                "status":"OPEN",
                "type":"energetic"
            },
            {
                "id":"N5",
                "status":"OPEN",
                "type":"hot"
            }
        ]
    }
]

b = [
    {
        "name": "harry",
        "properties": [
            {
                "id":"N3",
                "type":"energetic",
                "language": "english"
            },
            {
                "id":"N6",
                "status":"OPEN",
                "type":"cool"
            }
        ]
    }
]

a_names = set()
a_prop_ids_by_name = {}
a_by_name = {}
for ao in a:
    an = ao['name']
    a_names.add(an)
    if an not in a_prop_ids_by_name:
        a_prop_ids_by_name[an] = set()
    for ap in ao['properties']:
        api = ap['id']
        a_prop_ids_by_name[an].add(api)
    a_by_name[an] = ao

res = []

for bo in b:
    bn = bo['name']
    if bn not in a_names:
        res.append(bo)
    else:
        ao = a_by_name[bn]
        bp = bo['properties']
        for bpo in bp:
             if bpo['id'] not in a_prop_ids_by_name[bn]:
                 ao['properties'].append(bpo)
        res.append(ao)

print(res)

上面的想法是處理列表a的名稱和 ID。 names 和 ids-by-name 是 Python set的實例。 所以成員總是唯一的。

一旦你有了這些集合,你就可以對列表b的內容進行左外連接。

b 中存在 object 而b中不a (即共享一個通用name ),在這種情況下,您可以將 object 按原樣添加到結果中。 但是,如果b中有一個 object 確實存在於a (共享一個公共name )中,那么您將迭代該對象的id值並查找尚未在a ids-by-name 集中的 ids。 您將缺少的屬性添加到a中,然后將處理后的 object 添加到結果中。

Output:

[{'name': 'harry', 'properties': [{'id': 'N3', 'status': 'OPEN', 'type': 'energetic'}, {'id': 'N5', 'status': 'OPEN', 'type': 'hot'}, {'id': 'N6', 'status': 'OPEN', 'type': 'cool'}]}]

這不會對輸入進行任何錯誤檢查。 這依賴於每個 object 中唯一的name值。因此,如果您在兩個列表中的對象中有重復的鍵,您可能會得到垃圾(不正確或意外的輸出)。

這是其中一種方法:

a = {
   "name":"harry",
   "properties":[
      {
         "id":"N3",
         "status":"OPEN",
         "type":"energetic"
      },
      {
         "id":"N5",
         "status":"OPEN",
         "type":"hot"
      }
   ]
}
b = {
   "name":"harry",
   "properties":[
      {
         "id":"N3",
         "type":"energetic",
         "language": "english"
      },
      {
         "id":"N6",
         "status":"OPEN",
         "type":"cool"
      }
   ]
}

# Create dic maintaining the index of each id in resp dict
a_ids = {item['id']: index for index,item in enumerate(a['properties'])} #{'N3': 0, 'N5': 1}
b_ids = {item['id']: index for index,item in enumerate(b['properties'])} #{'N3': 0, 'N6': 1}

# Loop through one of the dict created
for id in a_ids.keys():
    # If same ID exists in another dict, update it with the key value
    if id in b_ids:
        b['properties'][b_ids[id]].update(a['properties'][a_ids[id]])
    # If it does not exist, then just append the new dict
    else:
        b['properties'].append(a['properties'][a_ids[id]])
        
        
print (b)

Output:

{'name': 'harry', 'properties': [{'id': 'N3', 'type': 'energetic', 'language': 'english', 'status': 'OPEN'}, {'id': 'N6', 'status': 'OPEN', 'type': 'cool'}, {'id': 'N5', 'status': 'OPEN', 'type': 'hot'}]}

暫無
暫無

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

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