递归合并字典,以便将具有共享密钥的元素合并到列表中 [英] Recursively merge dicts so that elements with shared key are combined into a list

查看:94
本文介绍了递归合并字典,以便将具有共享密钥的元素合并到列表中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个要合并的字典:

I have two dicts that I want to merge:

a = {"name": "john",
     "phone":"123123123",
     "owns": {"cars": "Car 1", "motorbikes": "Motorbike 1"}}

b = {"name": "john",
     "phone":"123",
     "owns": {"cars": "Car 2"}}

如果ab在相同的嵌套级别上具有一个公用密钥,则结果应该是一个列表,其中包含两个值,将其指定为共享密钥的值.

If a and b have a common key on the same nesting level, the result should be a list, with both values in it, which is assigned as the value for the shared key.

结果应如下所示:

{"name": "john",
 "phone":["123123123","123"],
 "owns": {"cars": ["Car 1", "Car 2"], "motorbikes": "Motorbike 1"}}

使用a.update(b)无效,因为它会用b的共享值覆盖a的共享值,因此结果如下:

Using a.update(b) does not work since it overwrites the shared value of a with the shared value of b, such that result is something like this:

{'name': 'john', 'phone': '123', 'owns': {'cars': 'Car 2'}}

目标是在不覆盖的情况下合并字典,并保留与特定键相关的所有信息(在任一字典中).

The goal is to merge the dicts without overwriting and to keep all information related to a specific key (in either of the dicts).

推荐答案

通过递归,您可以构建实现此目的的字典理解.

With recursion, you can build a dictionary comprehension that accomplishes that.

此解决方案还考虑到您以后可能希望合并两个以上的词典,从而在这种情况下将值列表弄平.

This solution also takes into account that you might want to later merge more than two dictionaries, flattening the list of values in that case.

def update_merge(d1, d2):
    if isinstance(d1, dict) and isinstance(d2, dict):
        # Unwrap d1 and d2 in new dictionary to keep non-shared keys with **d1, **d2
        # Next unwrap a dict that treats shared keys
        # If two keys have an equal value, we take that value as new value
        # If the values are not equal, we recursively merge them
        return {
            **d1, **d2,
            **{k: d1[k] if d1[k] == d2[k] else update_merge(d1[k], d2[k])
            for k in {*d1} & {*d2}}
        }
    else:
        # This case happens when values are merged
        # It bundle values in a list, making sure
        # to flatten them if they are already lists
        return [
            *(d1 if isinstance(d1, list) else [d1]),
            *(d2 if isinstance(d2, list) else [d2])
        ]

示例:

a = {"name": "john", "phone":"123123123",
     "owns": {"cars": "Car 1", "motorbikes": "Motorbike 1"}}
b = {"name": "john", "phone":"123", "owns": {"cars": "Car 2"}}

update_merge(a, b)
# {'name': 'john',
#  'phone': ['123123123', '123'],
#  'owns': {'cars': ['Car 1', 'Car 2'], 'motorbikes': 'Motorbike 1'}}

示例合并了两个以上对象:

Example with more than two objects merged:

a = {"name": "john"}
b = {"name": "jack"}
c = {"name": "joe"}

d = update_merge(a, b)
d = update_merge(d, c)

d # {'name': ['john', 'jack', 'joe']}

这篇关于递归合并字典,以便将具有共享密钥的元素合并到列表中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆