2011-11-29 36 views
3

今晚我在長時間的項目中工作太久了。但是我遇到了一個簡單的障礙。任何人都可以告訴我爲什麼這個代碼的工作方式是?這個python list清除循環有什麼問題?

我有兩個列表。我希望list2只包含不在list1中的數字。 從邏輯上看,這似乎應該工作。但它完全可以做到。爲什麼?

list1 = [1,2,3,4,5,6,7,8] 
list2 = [12,15,16,7,34,23,5,23,76,89,9,45,4] 


for ch in list2: 
    if ch in list1: 
     list2.remove(ch) 

return list2 

某種方式下,它返回: [15,7,5,23,76,9,4]

爲什麼呢?

我該如何完成我所需要的?

回答

8

當您修改正在迭代的序列時,它會產生意外的結果。我會這樣做,它利用快速set操作。

list2 = list(set(list2) - set(list1)) 

這是否是比使用列表理解更快或更慢取決於list1list2大小,以及是否可以讓一進一出set作爲多次初始化的一部分,而不是在一個循環。

+0

+1爲什麼部分。 – fncomp

+0

完美。謝謝 – tknickman

5

迭代時不要修改列表。

你想要什麼可以用列表理解直接表示:

list2 = [ch for ch in list2 if ch not in list1] 

它是更具可讀性,並用不同的解決方案集也不會從列表2中刪除重複或更改項目的順序。

更新:當列表1大,創建一組來自它實際上將加快東西:

list2 = [ch for ch in list2 if ch not in set(list1)] 
+0

這是一個好點。雖然你可能想把'list1'變成'set'。 –

1

這是一個有趣的問題。讓我解釋爲什麼發生這種情況。

當你在python中使用for a in list時,python依次查找列表的元素1,元素2等。所以它首先看到12並刪除它。然後它查看元素2,除了現在15是元素1並且16是元素2.它刪除了16.因此15從未被檢查並且留在列表中。然後它類似地跳過7並刪除34 ...

避免這種情況的方法當然不是在刪除元素的同一列表上進行迭代。您可以製作第二個列表的副本。檢查此副本中的成員是否在第一個列表中。如果不是,請將其從第二個列表中刪除。我相信已發佈的一些建議將對您有用。這是解釋。

+1

這也是我的想法,但代碼不應該刪除'12',因爲它不在'list1'中。 –

+0

讓我看看它。 –