如何在Python中高效合并两个字典而不重复?

1 投票
4 回答
97 浏览
提问于 2025-04-14 17:20

我正在做一个Python项目,需要把两个字典合并在一起,但我想确保合并后的结果没有重复的键,因为最终的结果应该是每个键都是唯一的,并且有对应的值。以下是我尝试过的方法:

dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
merged_dict = {**dict1, **dict2}

这个方法会覆盖重复键的值,但我想找到一种方法,要么防止出现重复,要么以特定的方式处理它们(比如,把值加在一起,或者保留较大的值)。

我搜索了一些解决方案,但大多数方法并没有按照我需要的方式处理重复项。有没有一种有效的Python方法,可以在合并字典的同时,根据自定义逻辑管理重复项呢?

环境:Ubuntu 20.04上的Python 3.8

4 个回答

1

因为你没有明确说明你想怎么处理重复项,这里有一个非常灵活的版本,可以让你随心所欲。它不会改变原来的字典,而且你可以在一次调用中合并任意数量的字典。

解决方案
from typing import Callable

def merge(oper:Callable, *args) -> dict:
    out = {}
    for d in filter(lambda x: isinstance(x, dict), args):
        for k,v in d.items():
            # None means this does not exist, ONLY create it
            if (x := out.get(k)) is None:
                out[k] = v
                continue
                
            out[k] = oper(x, v)
            
    return out
用法
import operator

d1 = dict(a=1, b=2, c=3)
d2 = dict(b=1, c=2, d=3)
d3 = dict(c=1, d=2, e=3)

print(merge(operator.add, d1, d2, d3)) # add duplicates
print(merge(max, d1, d2, d3))          # max of duplicates
输出
{'a': 1, 'b': 3, 'c': 6, 'd': 5, 'e': 3}
{'a': 1, 'b': 2, 'c': 3, 'd': 3, 'e': 3}

因为这个解决方案可以接受任何函数,你甚至可以自己编写一个。这个例子会把重复的项存储在一个列表里。

from typing import Any

def store(a:Any, b:Any) -> list:
    if not isinstance(a, list):
       a = [a]
    
    a.append(b)
    return a
    
print(merge(store, d1, d2, d3)) #{'a': 1, 'b': [2, 1], 'c': [3, 2, 1], 'd': [3, 2], 'e': 3}

数据不一定是数字。接下来的两个例子说明,使用这个解决方案,你几乎只受限于你的想象力。

字符串示例
dicts = (dict(a='h', b='w'),
         dict(a='e', b='o'),
         dict(a='l', b='r'),
         dict(a='l', b='l'),
         dict(a='o', b='d'))
            
print(merge('{}{}'.format, *dicts)) #{'a': 'hello', 'b': 'world'}
numpy示例
import numpy as np
import operator

d1 = dict(a=np.array([1, 2, 3]), b=np.array([4, 5, 6]))
d2 = dict(a=np.array([7, 8, 9]), b=np.array([10, 11, 12]))

print(merge(operator.mul, d1, d2)) #{'a': array([ 7, 16, 27]), 'b': array([40, 55, 72])}
2

这是我解决问题的一个变种:

def handle_duplicates(v1, v2):
    # Implement how would you like to deal with duplicates
    return [v1, v2]


def merge(d1: dict, d2: dict) -> dict:
    merged = d1 | d2
    for k in set(d1.keys()) & set(d2.keys()):
        merged[k] = handle_duplicates(d1[k], d2[k])

    return merged

通过进行一个 | 操作,我们得到了一个“预合并”的字典,这个字典包含了 d1d2 的值,其中 d2 的值优先。接着,在 for 循环中,我们利用集合交集的操作,找到两个字典中都存在的键,并按照我们想要的方式用新的值覆盖这些键。

>> merge({"a": 1, "b": 2}, {"a": 3})
{'a': [1, 3], 'b': 2}

或者,如果你喜欢一行代码的写法,这里有一个:

def merge(d1: dict, d2: dict) -> dict:
    return {
        k: handle_duplicates(d1[k], d2[k])
        if k in d1 and k in d2
        else d1.get(k) or d2.get(k)
        for k in set(d1.keys()) | set(d2.keys())
    }

不过,这个看起来有点复杂,个人来说我更喜欢第一个选项。

0

这是一种比评论中提到的某些方法更长的做法,但这里有一种你可以尝试的方法:

#The original dicts
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}

#Create a list and a set for the keys.  The set will be used with union to get unique keys
dict1keys=list(dict1.keys())
dict2keys=list(dict2.keys())
dict1keysset=set(dict1keys)
dict2keysset=set(dict2keys)

#Concatenate the two lists of keys
concatekey=dict1keys+dict2keys

#Get lists of values from original dicts
dict1vals=list(dict1.values())
dict2vals=list(dict2.values())

#Add the keys and values to a dataframe
keyValDF=pd.DataFrame()
keyValDF['Key']=dict1keys+dict2keys
keyValDF['Vals']=dict1vals+dict2vals

#Get the key list with each key represented only once
NewKeylst=list(dict1keysset.union(dict2keysset))

#Group the data by key
NewDF=keyValDF.groupby('Key').sum().reset_index()

#Put the columns back into a new dict with sums for each key
NewDict= dict(zip(NewDF['Key'], NewDF['Vals']))


#This is the df that we build the dict from
display(NewDF)

#This is the new dict
print(NewDict)

输出结果将是:

在这里输入图片描述

如果你想要最大值而不是总和,只需把'sum'改成'max',那么你的输出结果将是:

在这里输入图片描述

撰写回答