【问题标题】:Merge dictionaries with same key from two lists of dicts in python从python中的两个字典列表中合并具有相同键的字典
【发布时间】:2021-11-26 07:44:32
【问题描述】:

我有两个字典,如下所示。两个字典都有一个字典列表作为与其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"
      }
   ]
}

我想要达到的输出是:

   "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)

有人可以帮忙解决这个问题吗?

【问题讨论】:

  • @AlexWaygood 我的错。我很抱歉。它的两个字典

标签: python python-3.x dictionary


【解决方案1】:

这是一种方法:

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)

输出:

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

【讨论】:

    【解决方案2】:

    将这两个对象视为各自列表中的元素可能会有所帮助。也许您还有其他具有不同 name 值的对象,例如可能来自 JSON 格式的 REST 请求。

    然后您可以在 nameid 键上执行 left outer join

    #!/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。名称和 ids-by-name 是 Python set 的实例。所以成员总是独一无二的。

    一旦你有了这些集合,你就可以对列表b的内容进行左外连接。

    b 中有一个对象在a 中不存在(即共享一个公共name),在这种情况下,您将该对象按原样添加到结果中。但是,如果b 中有一个对象确实存在于a 中(共享一个公共name),那么您遍历该对象的id 值并查找尚未在a ids 中的ids-按名称集。您将缺少的属性添加到 a,然后将该处理后的对象添加到结果中。

    输出:

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

    这不会对输入进行任何错误检查。这依赖于每个对象的 name 值是唯一的。因此,如果您在两个列表中的对象中有重复的键,您可能会得到垃圾(不正确或意外的输出)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-20
      • 1970-01-01
      • 2019-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多