2011-02-10 65 views
5

我環路和刪除滿足我的條件的元素。但爲什麼不這樣做,如下所述?謝謝。如何安全通過列表中刪除從列表中的元素在Python

>>> a=[ i for i in range(4)] 
>>> a 
[0, 1, 2, 3] 
>>> for e in a: 
...  if (e > 1) and (e < 4): 
...   a.remove(e) 
... 
>>> a 
[0, 1, 3] 
>>> a=[ i for i in range(4)] 
>>> for e in a: 
...  if (e > -1) and (e < 3): 
...   a.remove(e) 
... 
>>> a 
[1, 3] 

回答

9

你在迭代它時不能改變某些東西。結果很奇怪,反直覺,幾乎從來沒有你想要的。事實上,許多收藏明確地禁止這樣做(例如套和字典)。

相反,遍歷一個副本(for e in a[:]: ...)或,而不是修改現有列表,過濾它獲取包含您想要的物品([e for e in a if ...])一個新的列表。請注意,在很多情況下,你不必再重複進行篩選,只用數據的生成合並的過濾。

5

爲什麼不直接在列表理解中做到這一點?例如。

[i for i in range(4) if i <= 1 or i >= 4] 

您也可以使用它從現有列表構造一個新列表,例如,

[x for x in a if x <= 1 or x >= 4] 
+0

這將返回應該實際刪除的項目。 – 2011-02-10 18:16:20

+0

@Sven對不起,我會修復它 – 2011-02-10 18:16:51

1

它是不是安全,而迭代雖然它從列表中刪除元素。爲此存在過濾功能。它需要一個函數(即承認一個參數)和一個可迭代(在這種情況下您的列表)。它返回相同類型的具有在施加於該元素的函數返回true的元素的新迭代(列表在這裏再次):

在你的情況,你可以使用lambda函數是這樣的:

a = filter(lambda x: x > 1 and x < 4, range(4)) 

或者,如果你已經列表:

a = range(4) 
a = filter(lambda x: x > 1 and x < 4, a) 

記住,如果你使用python3它會返回一個迭代器,而不是一個列表。

+0

對於這樣的簡單情況,我更喜歡`filter`上的列表理解。 – 2011-02-10 18:19:26

2

濾波的構思是一個很好的,但是它錯過其是某些列表可能非常大和元件以去除可能是非常小的數量的點。

在這種情況下,答案是要記住的元素列表索引中移除,然後通過索引列表,排序從大到小重複,刪除的元素。

+0

假設你有一個100萬的元素列表和4個被刪除。過濾它意味着洗牌大約100萬個元素,而您的建議平均需要洗牌兩次。當然,其他因素會意味着它不那麼簡單,但除非你確實計算了代碼的時間,否則我會堅持使用最簡單的(過濾),因爲如果有的話,你將不會獲得太多的收益複雜。 – Duncan 2011-02-10 18:56:45

2

想象它最簡單的方法是考慮迭代的列表偏移,而不是實際的項目工作 - 做一些事情的第一個項目,那麼第二項,再單擊第三項,直到用完項目。如果更改列表中的項目的數量,它改變列表中的所有剩餘項目的偏移量:

lst = [1,2,3,4] 
for item in lst: 
    if item==2: 
     lst.remove(item) 
    else: 
     print item 
print lst 

結果

1 
4 
[1,3,4] 

這是有道理的,如果你通過它一步像這樣:

[1,2,3,4] 
^ 
first item is not 2, so print it -> 1 

[1,2,3,4] 
^
    second item is 2, so remove it 

[1,3,4] 
    ^
    third item is 4, so print it -> 4 

唯一真正的解決辦法是當你迭代它不改變列表中的項目數量。將要保留的項目複製到新列表中,或跟蹤要刪除的值,並在單獨的通道中執行按值刪除。

相關問題