如何在Python中将字典合并在一起?


89
d3 = dict(d1, **d2)

我了解这将合并词典。但是,它独特吗?如果d1与d2具有相同的密钥但值不同怎么办?我希望将d1和d2合并,但是如果有重复的键,则d1具有优先权。


9
请注意,**除非所有的关键字d2都是字符串,否则此技巧被认为是滥用关键字参数传递的方法。如果不是所有的键d2都是字符串,则这在Python 3.2和Python的替代实现(如Jython,IronPython和PyPy)中将失败。参见例如mail.python.org/pipermail/python-dev/2010-April/099459.html
马克·迪金森

Answers:


151

.update()如果您不再需要原始方法,则可以使用该方法d2

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

例如:

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

更新:

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


1
在这种情况下,如果发现有冲突的密钥,则d1元素应正确获得优先级
Trey Hunner,2010年

如果您仍然需要它,只需复制一份即可。d3 = d2.copy()d3.update(d1),但我希望看到d1 + d2已添加到语言中。
2010年

4
d1 + d2有问题,因为一本字典在冲突期间必须具有优先级,并且哪一本并不特别明显。
rjh 2010年

d1 + d2仅在Python获得多图的情况下才会实现,否则对于8字节键入增益,用户的含糊之处会造成混淆。
尼克·巴斯汀

在此示例中,您在字典中有对象:isinstance(int, object) is True但是deepcopy似乎没有必要。
Antony Hatchkins 2013年

43

在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}

这种行为不仅仅是实现的偶然。它在文档中保证:

如果在位置参数和关键字参数中都指定了键,则与关键字关联的值将保留在字典中。


3
您的示例将在Python 3.2和当前版本的Jython,PyPy和IronPython中失败(产生TypeError):对于这些版本的Python,当传递带有**符号的字典时,该字典的所有键都应为字符串。有关更多信息,请参见从mail.python.org/pipermail/python-dev/2010-April/099427.html开始的python-dev线程。
马克·迪金森

@Mark:感谢大家的注意。我已经编辑了代码以使其与非CPython实现兼容。
unutbu 2010年

3
如果您的键是字符串和数字的元组,它将失败。例如 d1 = {(1,'a'):1,(1,'b'):0,} d2 = {(1,'a'):1,(2,'b'):2,(2, 'a'):1,}
MySchizoBuddy

关于解包语法,请参阅此文章以了解python 3.5中即将发生的更改。
Ioannis Filippidis 2015年

我要说d = dict(**d1, **d2)的是可行的,但这就是@IoannisFilippidis在其评论中引用的内容。也许在这里包括代码片段会更加清晰,所以在这里。
dwanderson

14

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

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

否则,反转d2d1


1

我的解决方案是定义合并功能。它并不复杂,仅花费一行。这是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()
{}

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


1
一个简单的循环(其中包含一个.update调用)(merged={}后跟for d in dict: merged.update(d))将更短,更易读且更有效。
Mark Dickinson

1
或者,如果您真的想使用reducelambdas,那又如何return reduce(lambda x, y: x.update(y) or x, dicts, {})呢?
Mark Dickinson

1
您可以在shell中试用您的代码,看看是否正确。我试图做的是编写一个函数,该函数可以使用相同功能的各种字典参数。最好不要在lambda下使用x.update(y),因为它总是返回None。而且我正在尝试编写一个更通用的功能merge_with,该功能采用各种数量的字典参数并使用提供的功能处理重复的键。完成后,将其发布到解决方案更相关的另一个线程中。
赵雷

这是我编写更通用解决方案的链接。欢迎来看看。
赵雷


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合并(优先于d1值)来修改d2 的运算符:

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


0

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

虽然,我想指出这dict(d1, **d2)实际上是合并字典的一种不好的方法,因为关键字参数必须是字符串,因此如果您输入dict诸如此类,它将失败:

{
  1: 'foo',
  2: 'bar'
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.