这似乎是一项简单的任务:
我正在尝试合并2个词典而不覆盖值但是APPENDING。
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(正确),元组数= 6(正确)
它将b中的元组[(5,5)]
附加到a。我不知道为什么会发生这种情况,因为我编码的只是将所有内容写入完整的字典“all”。
谁能告诉我它在哪里改变dict(a)???????
非常欢迎任何帮助。
答案 0 :(得分:4)
使用.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会导致更改在两个位置都可见。
使用简单变量而不是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
和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()
调用的结果)不同。
答案 1 :(得分:4)
如果您想要合并的第三个字典,我会使用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)
输出
defaultdict(<type 'list'>, {1: [(1, 1)], 2: [(2, 2), (3, 3)], 3: [(4, 4), (5, 5)], 4: [(6, 6)]})
答案 2 :(得分:1)
作为对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]
点到{{} 1}}列表。它不是副本,而是a[k]
的引用:它们基本上是同一个对象。在下一次迭代中,a[k]
已定义,您追加到它:但当all[k]
指向all[k]
时,您最终还会附加到a[k]
。
您想要避免使用a[k]
。你可以尝试:
all[k] = a[k]
(注意for k in a.keys():
if k not in all:
all[k] = []
all[k].extend(a[k])
而不是extend
,正如@Martijn Pieters所指出的那样。在这里,您永远不会append
指向all[k]
,因此您是安全的。 @Martijn Pieters的回答更加简洁优雅,所以你应该选择它。