遍历不断变化的字典



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

只是试图迭代字典给了我RuntimeError: dictionary changed size during iteration.搜索错误消息将我引向另一个问题,建议的解决方案是在开始迭代之前复制键列表。

然而,在我的方案中,这只是部分答案,因为我不仅需要迭代原始键,还需要迭代在迭代时添加的键。我需要的代码仅在没有更多键添加到字典时才终止,并且它已处理字典中已有的任何键。

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

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中不起作用。我发现了一个关于在 python 的 while 循环中使用赋值作为条件的问题。但是提出的答案似乎都不适用于我的场景。

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

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

这样更好吗?更 糟?我想由你决定。

也许你可以改用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

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

我将代码重写为:

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

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

最新更新