2

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

我正在尝试合并 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(正确),元组数全部 = 6(正确)

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

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

非常欢迎任何帮助。

4

3 回答 3

6

使用.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]

此外,您可以使用以下方法循环遍历两者的键a和值:bitertools.chain

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不受影响。在您的代码中,您不会创建列表的副本;相反,您复制了对列表的引用。最后,thealladict 值都指向相同的列表,并且在这些列表上使用 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()调用结果)不同。

于 2012-08-25T11:05:48.343 回答
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)]})
于 2012-08-25T11:08:46.760 回答
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] 指向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])

(注意@Martijn Pieters 所指出extend的,而不是)。append在这里,你永远不需要all[k]指向a[k],所以你是安全的。不过,@Martijn Pieters 的回答更加简洁和优雅,所以你应该接受它。

于 2012-08-25T12:57:56.123 回答