Skip to main content
 首页 » 编程设计

python之合并字典而不覆盖值

2025年05月04日11jackei

这似乎是一个简单的任务:

我正在尝试合并 2 个字典而不覆盖值但附加。

a = {1: [(1,1)],2: [(2,2),(3,3)],3: [(4,4)]}  
b = {3: [(5,5)], 4: [(6,6)]} 

元组数a = 4,元组数b = 2

这就是我挑出这些选项的原因,因为它们正在覆盖:

all = dict(a.items() + b.items())  
all = dict(a, **b) 
all = a.update([b]) 

以下解决方案工作得很好,但它还会将值附加到我的原始字典 a:

all = {} 
 
for k in a.keys(): 
    if k in all: 
        all[k].append(a[k]) 
    else: 
        all[k] = a[k] 
 
 
for k in b.keys(): 
    if k in all: 
        all[k].append(b[k]) 
    else: 
        all[k] = b[k] 

输出=

a = {1: [(1, 1)], 2: [(2, 2), (3, 3)], 3: [(4, 4), **[(5, 5)]**]} 
b = {3: [(5, 5)], 4: [(6, 6)]} 
c = {1: [(1, 1)], 2: [(2, 2), (3, 3)], 3: [(4, 4), [(5, 5)]], 4: [(6, 6)]} 

元组数a = 5 !!!!!,元组数b = 2(正确),元组数all = 6(正确)

它将元组 [(5,5)] 从 b 附加到 a。我不知道为什么会发生这种情况,因为我正在编写的所有代码都是将所有内容写入完整的字典“全部”。

谁能告诉我它到底在哪里改变了 dict(a) ????????

非常欢迎任何帮助。

请您参考如下方法:

使用.extend代替 .append 将列表合并在一起。

>>> example = [1, 2, 3] 
>>> example.append([4, 5]) 
>>> example 
[1, 2, 3, [4, 5]] 
>>> example.extend([6, 7]) 
>>> example 
[1, 2, 3, [4, 5], 6, 7] 

此外,您可以使用 itertools.chain 循环遍历 a 和 b 的键和值。 :

from itertools import chain 
all = {} 
for k, v in chain(a.iteritems(), b.iteritems()): 
    all.setdefault(k, []).extend(v) 

.setdefault()查找一个键,如果它不存在,则将其设置为默认值。或者你可以使用 collections.defaultdict隐含地做同样的事情。

输出:

>>> a 
{1: [(1, 1)], 2: [(2, 2), (3, 3)], 3: [(4, 4)]} 
>>> b 
{3: [(5,5)], 4: [(6,6)]} 
>>> all 
{1: [(1, 1)], 2: [(2, 2), (3, 3)], 3: [(4, 4), (5, 5)], 4: [(6, 6)]} 

请注意,因为我们现在首先为每个键创建一个干净的新列表,然后扩展,所以您在 a 中的原始列表不受影响。在您的代码中,您没有创建列表的副本;相反,您复制了对列表的引用。最后,all 和 a dict 值都指向相同的列表,并且在这些列表上使用 append 会导致更改在两个地方都可见。

用简单的变量而不是字典很容易证明这一点:

>>> foo = [1, 2, 3] 
>>> bar = foo 
>>> bar 
[1, 2, 3] 
>>> bar.append(4) 
>>> foo, bar 
([1, 2, 3, 4], [1, 2, 3, 4]) 
>>> id(foo), id(bar) 
(4477098392, 4477098392) 

foo 和bar 都指向同一个列表,列表没有被复制。要改为创建副本,请使用 list() 构造函数或使用 [:] 切片运算符:

>>> bar = foo[:] 
>>> bar.append(5) 
>>> foo, bar 
([1, 2, 3, 4], [1, 2, 3, 4, 5]) 
>>> id(foo), id(bar) 
(4477098392, 4477098536) 

现在 bar 是列表的一个新副本,更改在 foo 中不再可见。两个列表的内存地址(id() 调用的结果)不同。