2012-12-13 73 views
0

我有一個帶時間戳的字典,我想遍歷它並刪除過期的項目(使用Python) 我該如何做到最好? 此代碼給我RuntimeError:字典中迭代改變大小:如何從迭代的字典中刪除項目?

for key, value in img_dict.iteritems() : 
     if (time.time()-float(img_dict[key])) >= stale_img: 
      logger.debug('STALE IMAGE FROM '+hexlify(key)+ ' - GOT CLOSED NOW!') 
      del img_dict[key] 
      data_upload = True 
+1

嘗試'img_dict.items()' – JBernardo

+2

這不是你的問題,但你爲什麼要在img_dict.iteritems使用'關鍵,值():'的',而不是在img_dict鍵:' ,假設你沒有在任何地方使用'value',並且實際上明確地在做'img_dict [key]'? – abarnert

回答

4

在遍歷他們不能修改的集合。

大約有這幾個方面:

  • (0)重新考慮你的設計,看看你是否需要這樣做。
  • (1)不要修改集合;相反,建立一個新的過濾收集。
  • (2)不要遍歷集合;而是迭代集合的副本
  • (2.5)對於字典,迭代鍵的副本並顯式獲取值。

請注意,儘管迭代了項目,但您已經明確地獲取了值,因此沒有理由在此處使用#2。

下面是另外兩個的實現:

new_img_dict = {} 
for key in img_dict: 
    if (time.time()-float(img_dict[key])) >= stale_img: 
     logger.debug('STALE IMAGE FROM '+hexlify(key)+ ' - GOT CLOSED NOW!') 
     data_upload = True 
    else: 
     new_img_dict[key] = img_dict[key] 
img_dict = new_img_dict 

或者:

for key in img_dict.keys(): 
    if (time.time()-float(img_dict[key])) >= stale_img: 
     logger.debug('STALE IMAGE FROM '+hexlify(key)+ ' - GOT CLOSED NOW!') 
     del img_dict[key] 
     data_upload = True 

(如果你想這是Python 3的兼容,而不是img_dict.keys(),做img_dict.keys()[:]。)

那麼,你如何在兩者之間進行選擇?

第一個通常更容易推理 - 通常,不可變對象和純操作很容易推理。例如,如果您在某個地方拋出異常,則img_dict將始終具有原始版本或完整版本,而不是介於兩者之間的一半。當然,你不必思考在迭代它的時候改變什麼的意思。但是,在極少數情況下,很難將「將所有foo」刪除的算法轉換爲「copy foo not foo」算法。

第一個是通常也更容易改寫爲理解(或像filter高階函數的調用),變成一個發電機,重構拉出獨立的功能,等等

對於性能,第一個通常會更快,使用更少的內存,如果你過濾了很多值,而第二個通常會更好,如果你保持大多數價值。 (對於不同的收集類型,截止點是不同的,通常情況下,它很少重要,如果是這樣的話,應該寫兩種方式和配置文件。)

回到#0,我認爲它可能適用於這種情況。你正在穿過所有的鑰匙,看看是否有太舊的鑰匙,以便將它們移除。如果您使用了排序列表或優先級隊列,則不必這樣做。現在,如果您需要更頻繁地使用集合作爲dict而不是您需要刷新舊值,那麼您可能會獲得更多的成本,而不是從更改數據結構中獲益。但爲什麼不都有?如果你有按鍵的排序列表,在字典映射鍵到值之上,那麼你可能只是這樣做:

for key in img_sorted_key_list: 
    if time.time() - float(key) > stale_img: 
     break 
    del img_dict[key] 

或者更簡單地說:

stale_time = time.time() - stale_img 
for key in itertools.takewhile(lambda key: float(key) < stale_time, 
           img_sorted_key_list): 
    del img_dict[key] 

而且你可以換了排序的關鍵列表和字典一起成爲一個不錯的Cache類或東西。

1

看看這個例子。也許它會有幫助。請記住,當您從列表或字典中刪除元素時,從末尾開始。避免使用iteritems()方法。

keysMap = [ 
     {"key": 1 }, 
     {"key" : 2 }, 
     {"key" : 3 }, 
     {"key" : 4 }, 
     {"key" : 5 }, 
     {"key" : 6 } 
     ] 
i=len(keysMap)-1 
while i > 0 : 
    key = keysMap[i] 
    if key["key"]==2 : 
     del(keysMap[i]) 
    i=i-1 

# Printing the object data after deleting element key=2  
while i < len(keysMap) : 
    key = keysMap[i] 
    print key 
    i=i+1