【问题标题】:Updating a python dictionary while adding to existing keys?在添加到现有键的同时更新 python 字典?
【发布时间】:2013-05-20 16:16:46
【问题描述】:

我正在寻找最有效和 Pythonic(主要是有效)的方式来更新字典,但如果存在现有键,则保留旧值。比如……

myDict1 = {'1': ('3', '2'), '3': ('2', '1'), '2': ('3', '1')}
myDict2 = {'4': ('5', '2'), '5': ('2', '4'), '2': ('5', '4')}

myDict1.update(myDict2) gives me the following....

{'1': ('3', '2'), '3': ('2', '1'), '2': ('5', '4'), '5': ('2', '4'), '4': ('5', '2')}

请注意键“2”如何存在于两个字典中,并且曾经具有值(“3”,“1”),但现在它具有来自 myDict2 中的键的值(“5”,“4”)?

有没有办法以有效的方式更新字典,以便键 '2' 最终具有值('3'、'1'、'5'、'4')? #不分先后

提前致谢

【问题讨论】:

  • 不,没有简单的方法可以做到这一点。您必须迭代键并合并值。
  • 很遗憾,感谢您的回复。
  • 对我来说,您似乎正在代表一个带有邻接列表的图形...那么如果 '2':('3','1')'2':('5','3') 合并呢?结果列表中会出现双倍的'3's 吗?
  • @Billiska 然后 {'3': ['1', '5'], '1': ['3'], '5':[3]}

标签: python performance dictionary


【解决方案1】:

我认为最有效的方法是这样的:

for k, v in myDict2.iteritems():
    myDict1[k] = myDict1.get(k, ()) + v

但不幸的是,没有update 等效于您要执行的操作。

【讨论】:

  • 我现在会尝试这种方法,看看它是否可以处理非常大的字典并回复您。感谢您的回复。
  • @Clay 我已经更新了我的答案,这样你的整体迭代次数就会减少,可能值得尝试我的新解决方案。然而,在某些时候处理大量数据会花费大量时间。
  • 谢谢你的回答,我想我会去的
【解决方案2】:

2 次就地更新操作有什么问题?

myDict2.update(myDict1)
myDict1.update(myDict2)

说明: 第一次更新将用 myDict1 中的值覆盖已经存在的键,并在 myDict2 中插入所有不存在的键值对。

第二次更新将用来自 myDict2 的值覆盖 myDict1 中已经存在的键,由于第一次操作,这些值实际上是来自 myDict1 本身的值。插入的任何新键值对都将来自原始 myDict2。

这当然取决于您不关心保留 myDict2 的事实

更新:使用 python3,您无需触摸 myDict2 即可完成此操作

myDict1 = {**myDict1, **myDict2, **myDict1}

实际上是一样的

myDict1 = {**myDict2, **myDict1}

输出

{'1': ('3', '2'), '3': ('2', '1'), '2': ('3', '1'), '4': ('5', '2'), '5': ('2', '4')}

【讨论】:

  • 2 in place 不适用于所有情况:例如 myDict1: { "pg": { "username": "foo", "password": "bar"} } myDict2: {"pg": {"host": "localhost"} myDict2.update(myDict1) myDict2: { "pg": { "username": "foo", "password": "bar"} } myDict1.update(myDict2) myDict1: { "pg ": { "username": "foo", "password": "bar"} }
【解决方案3】:

合并大型字典的最快方法是引入一个中间对象,该对象的行为就像字典被合并而不实际合并它们一样(请参阅@Raymond Hettinger's answer):

from collections import ChainMap

class MergedMap(ChainMap):
    def __getitem__(self, key):
        result = []
        found = False
        for mapping in self.maps:
            try:
                result.extend(mapping[key])
                found = True
            except KeyError:
                pass
        return result if found else self.__missing__(key)

merged = MergedMap(myDict1, myDict2)

是否适用取决于你以后想如何使用组合的dict。

为了方便提供完整的MutableMapping接口,它使用Python 3.3+中的collections.ChainMap;你可以只实现你在旧 Python 版本上使用的部分。

【讨论】:

    【解决方案4】:

    也许defaultdict 会有所帮助

    from collections import defaultdict
    myDict0= {'1': ('3', '2'), '3': ('2', '1'), '2': ('3', '1')}
    myDict2 = {'4': ('5', '2'), '5': ('2', '4'), '2': ('5', '4')}
    myDict1 = defaultdict(list)
    for (key, value) in myDict0.iteritems():
         myDict1[key].extend(value)
    
    for (key, value) in myDict2.iteritems():
         myDict1[key].extend(value)
    
    print myDict1
    defaultdict(<type 'list'>, {'1': ['3', '2'], '3': ['2', '1'], '2': ['3', '1', '5', '4'], '5': ['2', '4'], '4': ['5', '2']})
    

    【讨论】:

      【解决方案5】:

      不,恐怕没有简单的方法来做到这一点。

      最好的方法可能是迭代和合并。比如:

      for key in myDict1.iterkeys():
          # Thank you to user2246674 and Nolen Royalty to help me optimise this in their comments 
          if key in myDict2:
              myDict2[key] = myDict2[key] + myDict1[key]
          else:
              myDict2[key] = myDict1[key]
      

      【讨论】:

      • 感谢您的回复,您的回答就像一个魅力,但我有一本包含 100000 多个键的字典,这就是为什么我正在寻找一种有效的就地方法。
      • 是的,抱歉 - 我刚刚尝试了 200,000 个密钥,你是对的。需要一段时间!对不起:-(
      • if key in myDict2if key in myDict2.iterkeys() 更有效。 key in myDict2 是 O(1),而 key in myDict2.iterkeys() 是 O(n),其中 n 是 myDict2 的长度。我相信这就是@user2246674 试图传达的内容。
      • 这与 myDict2.update(myDict1) 具有完全相同的效果,这不是我正在寻找的内容
      猜你喜欢
      • 2013-10-11
      • 1970-01-01
      • 2023-03-11
      • 2020-04-12
      • 2022-01-22
      • 2013-09-19
      • 1970-01-01
      • 2017-12-17
      • 2015-05-01
      相关资源
      最近更新 更多