【问题标题】:Append a dictionary to a dictionary [duplicate]将字典附加到字典[重复]
【发布时间】:2012-02-14 09:34:34
【问题描述】:

我有两个现有的字典,我希望将其中一个“附加”到另一个。我的意思是,另一个字典的键、值应该被放入第一个字典中。例如:

orig = {
   'A': 1,
   'B': 2,
   'C': 3,
}

extra = {
   'D': 4,
   'E': 5,
}

dest = # Something here involving orig and extra

print dest
{
   'A': 1,
   'B': 2,
   'C': 3,
   'D': 4,
   'E': 5
}

我认为这一切都可以通过for 循环来实现(也许?),但是有没有一些字典方法或任何其他模块可以为我节省这项工作?我实际使用的字典真的很大...

【问题讨论】:

  • 一些答案​​指出orig.update(extra) 可以完成这项工作。请注意,如果extraorig 有重叠的键,则最终值将取自extra。例如,d1={1: 1, 2: 2}; d2={2: 'ha!', 3: 3}; d1.update(d2) 将导致 d1 包含 {1: 1, 2: 'ha!', 3: 3}

标签: python dictionary


【解决方案1】:

你可以的

orig.update(extra)

或者,如果您不想修改orig,请先复制一份:

dest = dict(orig)  # or orig.copy()
dest.update(extra)

请注意,如果 extra 和 orig 有重叠的键,则最终值将从 extra 中获取。例如,

>>> d1 = {1: 1, 2: 2}
>>> d2 = {2: 'ha!', 3: 3}
>>> d1.update(d2)
>>> d1
{1: 1, 2: 'ha!', 3: 3}

【讨论】:

  • 还有dict.copy(),像你的copy方法一样做浅拷贝。
  • 我以前见过那个 dict(**orig) 成语。与 dict(orig) 相比有什么优势?
  • 使用dict(**orig) 将创建一个新的临时字典,用作字典构造函数的关键字参数。然后,构造函数会将这个参数的值复制到自身中。因此,您使用dict(**orig) 创建了一个附加字典。当字典很大时,这很浪费,就像原来的问题一样。
  • 不过,我只是在标准 CPython (2.7) 上使用 timeit 进行了快速经验测试,而 dict(**orig) 的速度快。 YMMV,这取决于您的实现——但我不完全确定在这种情况下 ** 习语确实会在所有实现中产生额外的开销,可能是因为 dict 是一个内置类型。
  • 如果您的键不是有效的关键字参数,则会中断。例如。 x = {1: 1}; dict(**x)
【解决方案2】:

有两种方法可以将一个字典添加到另一个字典。

更新(原地修改orig

orig.update(extra)    # Python 2.7+
orig |= extra         # Python 3.9+

合并(创建一个新字典)

# Python 2.7+
dest = collections.ChainMap(orig, extra)
dest = {k: v for d in (orig, extra) for (k, v) in d.items()}

# Python 3
dest = {**orig, **extra}          
dest = {**orig, 'D': 4, 'E': 5}

# Python 3.9+ 
dest = orig | extra

请注意,这些操作是不可交换的。在所有情况下,后者是赢家。例如

orig  = {'A': 1, 'B': 2}
extra = {'A': 3, 'C': 3}

dest = orig | extra
# dest = {'A': 3, 'B': 2, 'C': 3}

dest = extra | orig
# dest = {'A': 1, 'B': 2, 'C': 3}

还需要注意的是,仅从 Python 3.7(和 CPython 3.6)开始订购 dicts。因此,在以前的版本中,字典中项目的顺序可能会有所不同。

【讨论】:

  • 为什么会这样?
  • 非常适合 1-deep level dict 合并!
【解决方案3】:

假设您不想更改 orig,您可以像其他答案一样进行复制和更新,或者您可以通过将两个字典中的所有项目传递给 dict 构造函数来一步创建新字典:

from itertools import chain
dest = dict(chain(orig.items(), extra.items()))

或者没有 itertools:

dest = dict(list(orig.items()) + list(extra.items()))

请注意,在 Python 3 上,您只需将 items() 的结果传递给 list(),在 2.x 上,dict.items() 已经返回一个列表,因此您只需执行 dict(orig.items() + extra.items())

作为一个更一般的用例,假设您有一个更大的 dicts 列表要组合成一个 dict,您可以执行以下操作:

from itertools import chain
dest = dict(chain.from_iterable(map(dict.items, list_of_dicts)))

【讨论】:

  • 其实我更喜欢这个,因为你可以用你想用它作为参数的同一个表达式“更新”一个字典,比如:SomeClass(**dict(args.items()+{'special':a_value,}.items()))
【解决方案4】:

dict.update() 看起来它会做你想做的事......

>> orig.update(extra)
>>> orig
{'A': 1, 'C': 3, 'B': 2, 'E': 5, 'D': 4}
>>> 

不过,也许您不想更新原始字典,而是在副本上工作:

>>> dest = orig.copy()
>>> dest.update(extra)
>>> orig
{'A': 1, 'C': 3, 'B': 2}
>>> dest
{'A': 1, 'C': 3, 'B': 2, 'E': 5, 'D': 4}

【讨论】:

    【解决方案5】:

    组合或合并两个字典的三行:

    dest = {}
    dest.update(orig)
    dest.update(extra)
    

    这将创建一个新字典 dest,而不修改 origextra

    注意:如果某个键在 origextra 中具有不同的值,则 extra 会覆盖 orig

    【讨论】:

    • 适用于 Python 2 和 Python 3。
    【解决方案6】:

    有 .update() 方法:)

    更新([其他]) 使用其他键/值对更新字典,覆盖现有键。返回无。

    update() 接受另一个字典对象或键/值对的可迭代对象(作为元组或其他长度为 2 的可迭代对象)。如果 指定关键字参数,然后更新字典 那些键/值对:d.update(red=1, blue=2)。

    在 2.4 版中更改:允许参数是键/值对的可迭代对象和允许的关键字参数。

    【讨论】:

      【解决方案7】:

      我想给出的答案是“使用collections.ChainMap”,但是我才发现它只是在Python 3.3中才添加的:https://docs.python.org/3.3/library/collections.html#chainmap-objects

      您可以尝试从 3.3 源代码中复制课程:http://hg.python.org/cpython/file/3.3/Lib/collections/init.py#l763

      这是一个功能较少的 Python 2.x 兼容版本(同一作者):http://code.activestate.com/recipes/305268-chained-map-lookups/

      您无需使用 dict.merge 将一个字典扩展/覆盖另一个字典,或者创建一个合并两者的附加副本,而是创建一个按顺序搜索两者的查找链。因为它不复制它包装的映射 ChainMap 使用很少的内存,并且可以看到以后对任何子映射的修改。因为顺序很重要,您还可以使用链来分层默认值(即用户首选项 > 配置 > env)。

      【讨论】:

        猜你喜欢
        • 2023-02-24
        • 1970-01-01
        • 2018-12-27
        • 1970-01-01
        • 1970-01-01
        • 2020-08-07
        • 2022-10-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多