[Python] 如何在迴圈中刪除list中的元素

在許多程式語言中,在迴圈中刪除串列(或陣列)中的元素,是一件蠻tricky的事。主要的原因是使用迴圈走訪串列時,你需要知道串列的大小,才能完成整個走訪的動作。但刪除元素會改變串列的大小,這會造成走訪的過程出錯。 在底下的程式碼中,迴圈會刪除串列中的偶數。但這樣的作法是錯的,因為元素刪除後,會造成 range(len(lst)): 這段判斷出錯,所以引發 index out of range 的問題。
lst = [1,2,4,8,13,16,19,22]

for i in range(len(lst)):
    if lst[i] % 2 == 0:
        del lst[i]


那要怎麼辦呢?


StackOverflow 已經有人給出了解答

方法一:

lst = [1,2,4,8,13,16,19,22]
x = lst
lst = [it for it in lst if it%2==0]
print(x)
print(lst)
這個作法會把 lst 中的元素掃描一次,將合乎刪除條件的元素排除,並且將剩下的元素「拷貝」一份,放到新的串列中。 注意在這個例子中,第1行的lst,和第3行的lst已經不一樣了。也就是說,第3行的lst指向的是另外一塊空間,而第2行中的x,則指向「原來」lst的空間。

於是你會發現第4行印出x時,印出的是舊的lst的資料,而第5行印出lst時,是印出將所有偶數都移除的串列。

但有時候我們專案中,某個串列同時會被許多變數參考到,例如前述的例子中,串列lst在第2行中,被x這個變數參考了。所以我們需要改變lst的元素時,還保留原來的參考。這時候就需要使用到方法2了。

方法二:

lst = [1,2,4,8,13,16,19,22]
x = lst
lst[:] = [it for it in lst if it%2==0]
print(x)
print(lst)

注意方法一及方法2只有第3行不一樣,但方法二這種作法會讓x還是參考到原來的lst。所以第4行及第5行印出來的內容是一樣的。 方法二的另一個好處是「拷貝」所帶來的效能負擔較輕,所以速度較快。

留言

這個網誌中的熱門文章

由 Pandas 的 DataFrame 中取得資料

[程式設計] C++ 的字串切割

[C++]在 cin 後呼叫 getline 所遇到的問題