如何将两个字典连接起来创建一个新的字典?

361

假设我有三个字典

d1={1:2,3:4}
d2={5:6,7:9}
d3={10:8,13:22}

我该如何创建一个新的d4,将这三个字典合并在一起?即:

d4={1:2,3:4,5:6,7:9,10:8,13:22}

38
d4 = {**d1, **d2, **d3} --> {1: 2, 3: 4, 5: 6, 7: 9, 10: 8, 13: 22} - mujad
5个回答

359
  1. 最慢的方法,且不能在Python3中使用:将items连接起来并在结果列表上调用dict

$ python -mtimeit -s'd1={1:2,3:4}; d2={5:6,7:9}; d3={10:8,13:22}' \
'd4 = dict(d1.items() + d2.items() + d3.items())'

100000 loops, best of 3: 4.93 usec per loop
  • 最快的方法:充分利用dict构造函数,然后使用update方法:

  • $ python -mtimeit -s'd1={1:2,3:4}; d2={5:6,7:9}; d3={10:8,13:22}' \
    'd4 = dict(d1, **d2); d4.update(d3)'
    
    1000000 loops, best of 3: 1.88 usec per loop
    
  • “Middling”:在一个最初为空的字典上循环调用update的一种方式:

  • $ python -mtimeit -s'd1={1:2,3:4}; d2={5:6,7:9}; d3={10:8,13:22}' \
    'd4 = {}' 'for d in (d1, d2, d3): d4.update(d)'
    
    100000 loops, best of 3: 2.67 usec per loop
    
    或者等价地说,一个复制构造函数和两个更新操作:
    $ python -mtimeit -s'd1={1:2,3:4}; d2={5:6,7:9}; d3={10:8,13:22}' \
    'd4 = dict(d1)' 'for d in (d2, d3): d4.update(d)'
    
    100000 loops, best of 3: 2.65 usec per loop
    

    我建议采用方法(2),特别是要避免使用方法(1)(它还需要O(N)的额外辅助内存来存储连接的项临时数据结构)。


    12
    我不明白为什么 d4 = dict(d1, **dict(d2, **d3)) 比 #2 操作慢,但事实上它确实比 #2 操作慢。 - Robert Rossney
    15
    如果处理小字典的话,我认为第一种方法更清晰明了。 - Baz
    47
    除非所有键都是字符串,否则选项2就是对Python 2实现细节的滥用(一些C实现的内置函数越过了关键字参数预期的检查)。在Python 3中(以及PyPy中),选项2将因为存在非字符串键而失败。 - Carl Meyer
    19
    我会把这样的说法改成更通俗易懂的语言,但不会改变原意。在Python 3中,d1.items() + d2.items()这段代码是无法正常运行的。 - Francisco
    39
    在Python 3.5及以上版本中,可以使用**符号:d1={1:2,3:4}; d2={5:6,7:9}; d3={10:8,13:22}; d4 = {**d1, **d2, **d3}。对于我来说,这比上述的#3或#4快近3倍(分别为0.228微秒每次循环,相对于#3或#4的0.661或0.595微秒)。如上所述,#1和#2在Python 3中不起作用。 - jared
    显示剩余9条评论

    200

    在Python 2中:

    d4 = dict(d1.items() + d2.items() + d3.items())
    

    在Python 3中(据说更快):

    d4 = dict(d1)
    d4.update(d2)
    d4.update(d3)
    

    这两个答案都来自之前的stackoverflow问题,该问题地址为此链接


    与其使用 d4 = dict(d1),我们可以使用 d4 = copy(d1) - Georg Schölly
    1
    @ds:似乎不起作用。也许你的意思是 from copy import copy; d4 = copy(d1) 或者 d4 = d1.copy() - John Machin
    44
    第一个版本在Python3上无法运行。 - Superbest
    1
    也许 d4 = d1.copy() - John Carrell
    2
    它在Python 3中可以工作,但你必须将dict_items对象转换为真正的list对象。这是另一种情况,Python 3优先考虑了轻微的性能优化而不是简单易用性。 - Carl Smith

    104
    你可以使用update()方法来构建一个包含所有项的新字典:
    dall = {}
    dall.update(d1)
    dall.update(d2)
    dall.update(d3)
    

    或者,在一个循环中:

    dall = {}
    for d in [d1, d2, d3]:
      dall.update(d)
    

    5
    更新不会建立一个新的字典,它会(如预期)更新原有的字典。 - A.J.Rouvoet
    9
    在这种情况下,“原始的”是指一个全新的空字典在dall中。这个新字典会被反复更新,以包含所有元素。dall被更改是有意为之的。 - sth
    2
    啊,我的评论只是针对你表达第一句话的方式。它暗示了一些并非事实的东西。虽然我承认打负分可能有点过分。 - A.J.Rouvoet
    逻辑上,我们可以使用更新来创建一个新的字典,如果我们不需要先前的字典,我们可以在 for 循环中使用 del d1 删除它们。 - Jay

    50

    这是一个一行代码(imports 不算在内 :)),可以轻松地推广为连接 N 个字典的方法:

    Python 3

    from itertools import chain
    dict(chain.from_iterable(d.items() for d in (d1, d2, d3)))
    

    并且:

    from itertools import chain
    def dict_union(*args):
        return dict(chain.from_iterable(d.items() for d in args))
    

    Python 2.6 & 2.7

    from itertools import chain
    dict(chain.from_iterable(d.iteritems() for d in (d1, d2, d3))
    

    输出:

    >>> from itertools import chain
    >>> d1={1:2,3:4}
    >>> d2={5:6,7:9}
    >>> d3={10:8,13:22}
    >>> dict(chain.from_iterable(d.iteritems() for d in (d1, d2, d3)))
    {1: 2, 3: 4, 5: 6, 7: 9, 10: 8, 13: 22}
    

    将N个字典拼接起来的通用方法:

    from itertools import chain
    def dict_union(*args):
        return dict(chain.from_iterable(d.iteritems() for d in args))
    

    我知道我来晚了,但我希望这能帮助到某些人。


    4
    "imports确实很重要,但这里的解决方案仍然很有趣。" - WestCoastProjects
    对于Python 3.6,应该使用d.items()而不是d.iteritems()。感谢您的贡献! - fang_dejavu
    对于追求完美的人来说,需要注意一点,Python3的第一个版本缺少了一个右括号。 - sandro scodelller
    @sandroscodelller 谢谢!已修复。 - ron rothman
    我不明白为什么Python没有实现"+"操作符来进行常见的字典连接。 - Shaun Han

    34

    使用字典构造函数

    d1={1:2,3:4}
    d2={5:6,7:9}
    d3={10:8,13:22}
    
    d4 = reduce(lambda x,y: dict(x, **y), (d1, d2, d3))
    

    作为一个函数

    from functools import partial
    dict_merge = partial(reduce, lambda a,b: dict(a, **b))
    

    通过使用dict.update()方法,可以消除创建中间字典的开销:

    from functools import reduce
    def update(d, other): d.update(other); return d
    d4 = reduce(update, (d1, d2, d3), {})
    

    1
    由于kwargs必须具有字符串键,因此在Python3中无法工作。 - scravy

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接