2013-02-15 63 views
1

這段代碼是否有潛在危險?它會混淆內部和外部迭代嗎?Python:從循環迭代器的內部和外部移除項目

for a in listA: 
      for b in listB: 
       if [... something...]: 
        ... something else... 
        listA.remove(a) 
        listB.remove(b) 
        break 
+3

是的,是的:它可能不會像你想要的那樣工作。請參閱http://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating-in-python – Emily 2013-02-15 16:20:34

+1

也許試試這個:'爲b在listb [:]:'它只會做一個列表的副本,你可以從你的原始列表中刪除。 – 2013-02-15 16:27:32

+0

是的,這聽起來比通過列表理解完成所有事情要好得多。我在上面的「......別的東西」中做了很多事情,壓縮上面鏈接中建議的所有內容會有點麻煩。 – 2013-02-15 16:32:07

回答

2

更改正在迭代的序列通常是Python中的反模式。雖然可以在特定情況下圍繞它跳舞,但最好查看是否可以構建僅包含所需項目的新列表(或字典)。

+0

實際上,我會同時刪除'a'和'b',然後調用'break',它會跳出內循環並移動到'listA'中的下一個元素。 – 2013-02-15 16:25:57

+0

啊,錯過了休息。你是對的,我會編輯我的答案(總體原則仍然適用)。 – jknupp 2013-02-15 16:28:41

6

這段代碼有潛在危險嗎?依靠。迭代時減小序列的大小會產生意想不到的行爲。

考慮這個例子

listA = [1,2,3,4] 

>>> for a in listA: 
    listA.remove(a) 
    print a 

因爲,在刪除的項目,全部超越它的項目,朝左,該項目是你所想象迭代會自動移動到下一個元素推

第一次迭代:

listA = [1,2,3,4] 
      ^
      | 
_____________| 

    listA.remove(a) 


    listA = [2,3,4] 
      ^
      | 
_____________| 


    print a 
    (outputs) 1 

第二次迭代:

listA = [2,3,4] 
      ^
       | 
_______________| 

    listA.remove(a) 

    listA = [2,4] 
      ^
       | 
_______________| 


    print a 
    (outputs) 3 

第三次迭代:

listA = [2,4] 
       ^
       | 
_________________| 

(Exits the Loop) 
+0

哦,所以我實際上是在跳項目,這正是我所遇到的行爲。非常感謝你的解釋。 – 2013-02-15 16:29:30

1

我同意jknupp - 在列表中刪除的項目可以比創建一個新的更貴。然而,另一個訣竅是向後做:

>>> l = range(5) 
>>> for a in reversed(l): 
...  print a 
...  l.remove(a) 
... 
4 
3 
2 
1 
0 
+0

嚴。將顛倒創建列表的本地副本?否則,我沒有看到差異。 – 2013-02-15 17:20:10

+0

不,reverse()創建一個反向迭代器。它的名字有點誤導,但至少它不太詳細。通過向後迭代,您已經傳遞了將由remove()取代的所有元素。 – tdelaney 2013-02-15 19:50:38