HOWTO · Python
從 Python 列表中刪除某元素的所有出現
在本文中,我們將看到如何在 Python 中從一個 List 中刪除一個元素的所有出現。
本頁內容
Python 列表可以多次儲存同一個值,而且每次出現都是位於列表中各自位置上的獨立項目。remove() 只會刪除第一個符合的項目,所以要清除某個值的所有出現就需要不同的做法。最直接的選項是列表推導式,它會建立一個只保留你想要項目的新列表;filter() 提供以判斷條件為基礎的替代方案,而當原始列表必須就地修改時,可以搭配迴圈使用 remove()。
使用列表推導式移除所有符合的項目
列表推導式會保留每個滿足條件的項目,並將通過篩選的項目收集到一個新列表中。執行這個範例:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
numbers = [1, 2, 3, 4, 2, 5, 2]
target = 2
filtered = [x for x in numbers if x != target]
print(filtered)
print(numbers)
[1, 3, 4, 5]
[1, 2, 3, 4, 2, 5, 2]
條件 x != target 會保留所有不等於 2 的值,因此三個 2 的副本都會從 filtered 中消失,而 numbers 仍保有原始資料。如果你想取代原始變數而不是保留兩個列表,可以將結果指派回它:numbers = [x for x in numbers if x != target]。其他綁定到舊列表物件的名稱仍會看到未過濾的項目,當呼叫方擁有該列表時,這通常正是你想要的行為。
如果該值從未出現在列表中,推導式仍會照常執行,並產生一個包含所有原始項目的列表:
numbers = [1, 3, 4, 5]
target = 2
filtered = [x for x in numbers if x != target]
print(filtered)
[1, 3, 4, 5]
這讓推導式可以安全地執行,不需要先檢查該值是否存在於列表中。
使用 filter() 移除所有符合的項目
filter() 函式會對每個項目套用一個判斷函式,並只產生判斷結果為真的項目。在 Python 3 中它回傳的是迭代器而非列表,所以當你需要一個可重複使用的列表時,要將其結果傳給 list()。判斷函式通常是一個 lambda,也就是一個用來比較每個項目與目標值的小型匿名函式:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
numbers = [1, 2, 3, 4, 2, 5, 2]
target = 2
filtered = list(filter(lambda x: x != target, numbers))
print(filtered)
[1, 3, 4, 5]
與推導式一樣,filter() 會建立一個新序列,並讓 numbers 保持不變;從未出現過的目標值會產生一個與輸入相同的列表。當判斷函式已經存在或需要重複使用時,請選用 filter();當條件只是像 x != target 這樣的一次性檢查時,則優先使用推導式。
使用 remove() 移除所有符合的項目
remove() 是一個列表方法,它只刪除第一個等於其引數的項目,並就地修改列表。單次呼叫絕對無法清除重複項目,所以要在該值仍然存在時重複呼叫它:
本節中的程式碼以及顯示的標籤或輸出仍為英文。
numbers = [1, 2, 3, 4, 2, 5, 2, 6]
target = 2
while target in numbers:
numbers.remove(target)
print(numbers)
[1, 3, 4, 5, 6]
每次迭代會為 target in numbers 掃描列表一次,並在 remove() 內部再掃描一次以找到第一個符合的項目,因此迴圈每刪除一個項目就會執行兩次搜尋。while 條件同時也是安全保障:當不再有符合的項目時,測試結果為假,迴圈便會停止。以不在列表中的值呼叫 remove() 會引發 ValueError,所以成員資格檢查——或等效的 numbers.count(target) 防護——正是讓重複移除安全進行的關鍵。當目標值從未出現在列表中時,迴圈主體根本不會執行,列表會保留其所有項目。
選擇合適的做法
- 需要過濾後的副本: 使用列表推導式。它只對列表掃描一遍、以行內方式寫出條件,並讓原始列表保持不變。
- 需要重複使用判斷函式: 使用
filter()搭配lambda或具名函式。其結果是惰性迭代器,所以當你需要具體的列表時,記得加上list()呼叫。 - 需要就地修改: 當其他程式碼必須在同一個列表物件上觀察到變更時,使用
while ... remove()迴圈。由於每個被刪除的項目都要付出一次成員資格掃描加上一次移除掃描的成本,在含有大量符合項目的長列表上,它比單次掃描的推導式做更多工作。
對於一般的列表大小,推導式是寫起來最清楚也最快的解法;迴圈額外的掃描只有在列表變大或移除操作頻繁執行時才會變得明顯。