使用for循环从字典中删除项目

9
我正在尝试从字典中删除值低于某个阈值的键值对。以下是一个简单的例子来说明我的意思:
my_dict = {'blue': 1, 'red': 2, 'yellow': 3, 'green': 4}

for color in my_dict:
    threshold_value = 3
    if my_dict[color] < threshold_value:
        del my_dict[color]

print(my_dict)

现在,我遇到了一个RuntimeError: dictionary changed size during iteration错误。没有什么大惊小怪的。我发帖问问题的原因是:

  1. 找出一个优雅的解决方案,不需要创建一个新字典(该字典仅保存值>= threshold的键)。

  2. 试着理解Python在这里的思路。我自己读到的方式是:“去到第一个键。这个键的值是否

3个回答

15

由于Python字典是以哈希表的方式实现的,因此您不应该依赖它们具有任何排序。键的顺序可能会在插入或删除键后无法预测地更改。因此,无法预测下一个键。为了安全起见,并防止人们遇到意外的结果,Python抛出RuntimeError

Python 2的dict.items方法返回键值对的副本,因此您可以安全地遍历它并通过键删除不需要的值,就像@wim在评论中建议的那样。例如:

for k, v in my_dict.items():
    if v < threshold_value:
        del my_dict[k]

然而,Python 3 的 dict.items 返回一个视图对象,它反映了对字典所做的所有更改。这就是上述解决方案仅适用于 Python 2 的原因。您可以将 my_dict.items() 转换为 listtuple 等),以使其与 Python 3 兼容。

另一种解决问题的方法是选择要删除的键,然后删除它们。

keys = [k for k, v in my_dict.items() if v < threshold_value]
for x in keys:
    del my_dict[x]

这适用于Python 2和Python 3。


2

字典是无序的。通过删除一个键,没有人能说下一个键是什么。因此,Python通常禁止从正在迭代的字典中添加或删除键。

只需创建一个新字典:

my_dict = {"blue":1,"red":2,"yellow":3,"green":4}
new_dict = {k:v for k,v in my_dict.iteritems() if v >= threshold_value}

正如我在原帖中所说,我不想创建一个新的字典。 - Optimesh
你要求一种优雅的方式,但你可以编写任何你喜欢的程序。 - Daniel

0

我想在迭代集合时修改它是一件难以正确实现的事情。考虑以下示例:

>>> list = [1, 2, 3, 4, 5, 6]
>>> for ii in range(len(list)):
  print list[ii]; 
  if list[ii] == 3:
    del list[ii]      
 1
 2
 3
 5
 6

请注意,在此示例中,数字4被完全省略了。在字典中也是如此,删除/添加条目可能会使定义迭代顺序的内部结构无效(例如,您删除了足够的条目以使哈希映射桶大小发生更改)。
要解决您的问题 - 只需创建新字典并将项目复制到其中即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接