迭代一个不断变化的字典

时间:2014-11-21 03:43:24

标签: python

我有一段python代码,它需要迭代字典中的所有键,循环体可能会更改字典。

试着在字典上迭代,给我RuntimeError: dictionary changed size during iteration。搜索错误消息会将我引导至another question,其中建议的解决方案是在开始迭代之前复制密钥列表。

在我的场景中,这只是一个部分答案,因为我不仅需要迭代原始键,还需要迭代在迭代时添加的键。我需要的代码只有在没有更多的密钥被添加到字典时终止,并且它已经处理了字典中已有的任何密钥。

到目前为止,我已经想出了这个:

processed = set()
while True:
    keys = set(dictionary) - processed
    if not keys:
        break
    for k in keys:
        processed.add(k)
        # Do something with k

这种做法看起来确实过于复杂。有什么方法可以简化它,并且仍然可以处理添加到字典中的所有键,而不是多次处理它们吗?

在其他一些语言中,while循环的前四行可以简单地写成:

while keys = set(dictionary) - processed:

然而,这在python中不起作用。我发现a question关于在python中的while循环中使用赋值作为条件。但是所提出的答案似乎都不适用于我的情景。

3 个答案:

答案 0 :(得分:2)

考虑相反的方法。跟踪仍需要处理的密钥,而不是已经处理过的密钥。

remaining = set(dictionary.items())

while remaining:
    key, value = remaining.pop()

    # process the item

    if item_to_add:
        dictionary[new_key] = new_value
        remaining.add((new_key, new_value))

这避免了每次迭代都会产生昂贵的设置差异操作。

如果你真的不知道在处理过程中添加了哪些键,那么你问题中的代码就是好的。编写它的方式略有不同:

keys = set(dictionary)
processed = set()

while keys:
    for k in keys:
        # Do something with k

    processed.update(keys)
    keys = set(dictionary) - processed

这样更好吗?更差?我想你可以决定。

答案 1 :(得分:2)

也许您可以使用OrderedDict代替。迭代时添加键没问题

>>> from collections import OrderedDict
>>> d = OrderedDict([(1, 2), (3, 4)])
>>> for k in d:
...     if k == 1:d[5] = 6
...     print(k)
... 
1
3
5

您是在更新密钥还是仅添加密钥?如果更新,您需要指定是否应该再次处理密钥

答案 2 :(得分:0)

我将我的代码重写为:

processed = set()
while set(dictionary) - processed:
    for k in set(dictionary) - processed:
        processed.add(k)
        # Do something with k

这确实复制了set(dictionary) - processed表达式,但仍然使代码更容易阅读。