合并词典而不覆盖值

2024-04-25 11:46:19 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我试图合并两个字典,不覆盖值,但附加。在

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

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

这就是为什么我选择这些选项,因为它们正在重写:

^{pr2}$

下面的解决方案可以很好地工作,但它也会将值附加到我的原始字典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。我不知道为什么会发生这种情况,因为我所编写的代码就是将所有内容写入完整的字典“all”。在

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

欢迎任何帮助。在


Tags: 代码in内容forif字典选项情况
3条回答

为了解释您的a发生变化的原因,请考虑您的循环:

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

因此,如果k还不在all中,则输入else部分,现在,all[k]指向a[k]列表。它不是副本,而是对a[k]的引用:它们基本上是同一个对象。在下一次迭代中,all[k]被定义,并且您可以附加到它:但是当all[k]指向a[k]时,您最终也会附加到a[k]。在

您希望避免all[k] = a[k]。你可以试试:

^{pr2}$

(注意extend,而不是@Martijn Pieters指出的append)。在这里,您永远不会all[k]指向a[k],所以您是安全的。@不过,马蒂恩·皮尔特斯的回答要简洁优雅得多,所以你应该随声附和。在

如果你想要第三本字典,我会用collection.defaultdict

from collections import defaultdict
from itertools import chain
all = defaultdict(list)
for k,v in chain(a.iteritems(), b.iteritems()):
    all[k].extend(v)

输出

^{pr2}$

使用^{}代替.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]

此外,还可以使用^{}a和{}的键和值进行循环:

^{pr2}$

^{}查找一个键,如果还没有,则将其设置为默认值。或者,您可以使用^{}隐式地执行相同的操作。在

输出:

>>> 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中的原始列表不会受到影响。在代码中,您不创建列表的副本,而是复制了对列表的引用。最后,alladict值都指向同一个列表,在这些列表上使用append将导致在这两个位置都可以看到更改。在

用简单变量代替dict很容易证明:

>>> 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和{}都引用同一个列表,该列表未被复制。要创建副本,请使用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()的结果)不同。在

相关问题 更多 >