2014-05-11 62 views
5

我試圖從字典中刪除項目,如果該項的值低於某個閾值。舉個簡單的例子,我的意思:使用for循環刪除字典中的項目

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. 找出是否有一個優雅的解決方案,不需要創建一個新的字典(只保存鍵與值> =閾值)。

  2. 試着理解Python的基本原理。我自己讀到的方式是:「轉到第一個鍵,鍵是< x的值嗎?如果是 - 刪除此鍵:值項,並繼續處理字典中的下一個鍵,如果不是 - 繼續下一把鑰匙而不做任何事「。換句話說,歷史上發生在前一個鍵上的事情不應該影響我下一步去的地方。我期待着下一個項目,不管過去。 我知道這很有趣(有人可能會說愚蠢的,我會給你的),但是Python對這個循環的「思考方式」是什麼?爲什麼它不起作用? Python如何將它自己大聲讀出來?只是試圖更好地理解語言......

回答

10

由於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返回view object反映到字典中的所有更改。這就是上述解決方案僅適用於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} 
+0

正如我在OP所說,我不想創建一個新的字典。 – Optimesh

+0

你問了一個優雅的方式。但是你可以編程任何你喜歡的東西。 – 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被完全忽略。它在字典中非常類似,刪除/添加條目可能會使定義迭代次序的內部結構無效(例如,您刪除了足夠的條目以便散列映射存儲區大小發生更改)。

爲了解決你的情況---只需創建新的字典和複製項目。至於