【问题标题】:How do I merge dictionaries together in Python?如何在 Python 中将字典合并在一起?
【发布时间】:2011-02-17 10:47:14
【问题描述】:
d3 = dict(d1, **d2)

我知道这会合并字典。但是,它是独一无二的吗?如果 d1 与 d2 具有相同的键但值不同怎么办?我希望 d1 和 d2 合并,但如果有重复键,则 d1 优先。

【问题讨论】:

标签: python dictionary


【解决方案1】:

Python 3.9 开始,运算符| 使用来自两个字典的合并键和值创建一个新字典:

# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d3 = d2 | d1
# d3: {'b': 2, 'c': 3, 'a': 1}

这个:

使用 d2 和 d1 的合并键和值创建一个新字典 d3。当 d2 和 d1 共享密钥时,d1 的值优先。


还要注意 |= 运算符,它通过合并 d1 来修改 d2,优先考虑 d1 的值:

# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d2 |= d1
# d2: {'b': 2, 'c': 3, 'a': 1}

【讨论】:

    【解决方案2】:

    我相信,如上所述,使用d2.update(d1) 是最好的方法,如果您仍然需要,也可以先复制d2

    不过,我想指出 dict(d1, **d2) 实际上是一种不好的合并字典的方法,因为关键字参数需要是字符串,因此如果您有 dict 则它将失败,例如:

    {
      1: 'foo',
      2: 'bar'
    }
    

    【讨论】:

      【解决方案3】:

      Trey Hunner has a nice blog post 概述了合并多个字典的几个选项,包括(对于 python3.3+)ChainMapdictionary unpacking

      【讨论】:

        【解决方案4】:

        如果不再需要原来的d2,可以使用.update()方法:

        使用其他键/值对更新字典,覆盖现有键。返回None

        例如:

        >>> d1 = {'a': 1, 'b': 2} 
        >>> d2 = {'b': 1, 'c': 3}
        >>> d2.update(d1)
        >>> d2
        {'a': 1, 'c': 3, 'b': 2}
        

        更新:

        当然,您可以先复制字典以创建新的合并字典。这可能是必要的,也可能不是必要的。如果您的字典中有复合对象(包含其他对象的对象,如列表或类实例),还应考虑copy.deepcopy

        【讨论】:

        • 在这种情况下,如果找到冲突的键,d1 元素应该正确获得优先级
        • 如果您仍然需要它,只需复制一份即可。 d3 = d2.copy() d3.update(d1) 但我希望看到 d1 + d2 被添加到语言中。
        • d1 + d2 是有问题的,因为在发生冲突时一本字典必须具有优先权,而哪一本不是特别明显。
        • d1 + d2 只有在 Python 获得多重映射的情况下才会被实现,否则对于 8 字节输入增益而言,用户的歧义性太令人困惑了。
        • 在本例中,您的字典中有对象:isinstance(int, object) is Truedeepcopy 似乎没有必要。
        【解决方案5】:

        我的解决方案是定义一个 merge 函数。它并不复杂,只需花费一条线。这是 Python 3 中的代码。

        from functools import reduce
        from operator import or_
        
        def merge(*dicts):
            return { k: reduce(lambda d, x: x.get(k, d), dicts, None) for k in reduce(or_, map(lambda x: x.keys(), dicts), set()) }
        

        测试

        >>> d = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
        >>> d_letters = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
        >>> merge(d, d_letters)
        {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
        >>> merge(d_letters, d)
        {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
        >>> merge(d)
        {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
        >>> merge(d_letters)
        {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
        >>> merge()
        {}
        

        它适用于任意数量的字典参数。如果这些字典中有任何重复的键,则参数列表中最右边字典中的键获胜。

        【讨论】:

        • 一个包含.update 调用的简单循环(merged={} 后跟for d in dict: merged.update(d))会更短、更易读、更高效。
        • 或者如果你真的想使用reducelambdas,return reduce(lambda x, y: x.update(y) or x, dicts, {})怎么样?
        • 您可以在 shell 中试用您的代码,看看它是否正确。我试图做的是编写一个函数,该函数可以采用具有相同功能的不同数量的字典参数。最好不要在 lambda 下使用 x.update(y),因为它总是返回 None。我正在尝试编写一个更通用的函数 merge_with ,它采用不同数量的字典参数并使用提供的函数处理重复键。完成后,我会将其发布到解决方案更相关的另一个线程中。
        • 这里是link,我在那里编写了更通用的解决方案。欢迎来看看。
        【解决方案6】:

        在 Python2 中,

        d1={'a':1,'b':2}
        d2={'a':10,'c':3}
        

        d1 覆盖 d2:

        dict(d2,**d1)
        # {'a': 1, 'c': 3, 'b': 2}
        

        d2 覆盖 d1:

        dict(d1,**d2)
        # {'a': 10, 'c': 3, 'b': 2}
        

        这种行为不仅仅是实施的侥幸。保证in the documentation:

        如果在 位置参数和作为关键字 参数,与关联的值 关键字保留在 字典。

        【讨论】:

        • 您的示例将在 Python 3.2 以及当前版本的 Jython、PyPy 和 IronPython 中失败(产生 TypeError):对于这些版本的 Python,当使用 ** 表示法传递 dict 时,所有该字典的键应该是字符串。有关更多信息,请参阅从 mail.python.org/pipermail/python-dev/2010-April/099427.html 开始的 python-dev 线程。
        • @Mark:感谢您的提醒。我已经编辑了代码以使其与非 CPython 实现兼容。
        • 如果你的键是字符串和数字的元组,它会失败。例如。 d1={(1,'a'):1, (1,'b'):0,} d2={(1,'a'):1, (2,'b'):2, (2, 'a'):1,}
        • 关于解包语法,请参阅 this post 了解 python 3.5 中即将发生的更改。
        • 我想说d = dict(**d1, **d2) 有效,但这就是@IoannisFilippidis 在他们的评论中提到的。也许在这里包括 sn-p 会更清楚,所以就在这里。
        【解决方案7】:

        如果您希望d1 在冲突中具有优先权,请执行以下操作:

        d3 = d2.copy()
        d3.update(d1)
        

        否则,反转d2d1

        【讨论】:

          猜你喜欢
          • 2011-10-05
          • 1970-01-01
          • 2016-09-25
          • 1970-01-01
          • 2011-11-16
          • 1970-01-01
          • 2022-11-15
          • 1970-01-01
          相关资源
          最近更新 更多