1. 程式人生 > 程式設計 >Python中list迴圈遍歷刪除資料的正確方法

Python中list迴圈遍歷刪除資料的正確方法

前言

初學Python,遇到過這樣的問題,在遍歷list的時候,刪除符合條件的資料,可是總是報異常,程式碼如下:

num_list = [1,2,3,4,5]
print(num_list)

for i in range(len(num_list)):
 if num_list[i] == 2:
  num_list.pop(i)
 else:
  print(num_list[i])

print(num_list)

會報異常:IndexError: list index out of range

原因是在刪除list中的元素後,list的實際長度變小了,但是迴圈次數沒有減少,依然按照原來list的長度進行遍歷,所以會造成索引溢位。

於是我修改了程式碼如下:

num_list = [1,5]
print(num_list)

for i in range(len(num_list)):
 if i >= len(num_list):
  break

 if num_list[i] == 2:
  num_list.pop(i)
 else:
  print(num_list[i])

print(num_list)

這回不會報異常了,但是列印結果如下:

[1,5]
1
4
5
[1,5]
[Finished in 0.441s]

雖然最後,list中的元素[2]確實被刪除掉了,但是,在迴圈中的列印結果不對,少列印了[3]。

思考了下,知道了原因,當符合條件,刪除元素[2]之後,後面的元素全部往前移,於是[3,5]向前移動,那麼元素[3]的索引,就變成了之前[2]的索引(現在[3]的下標索引變為1了),後面的元素以此類推。可是,下一次for迴圈的時候,是從下標索引2開始的,於是,取出了元素[4],就把[3]漏掉了。

把程式碼修改成如下,結果一樣,絲毫沒有改觀:

num_list = [1,5]
print(num_list)

for item in num_list:
 if item == 2:
  num_list.remove(item)
 else:
  print(item)

print(num_list)

既然知道了問題的根本原因所在,想要找到正確的方法,也並不難,於是我寫了如下的程式碼:

num_list = [1,5]
print(num_list)

i = 0
while i < len(num_list):
 if num_list[i] == 2:
  num_list.pop(i)
  i -= 1
 else:
  print(num_list[i])

 i += 1

print(num_list)

執行結果,完全正確:

[1,5]
1
3
4
5
[1,5]
[Finished in 0.536s]

我的做法是,既然用for迴圈不行,那就換個思路,用while迴圈來搞定。每次while迴圈的時候,都會去檢查list的長度(i < len(num_list)),這樣,就避免了索引溢位,然後,在符合條件,刪除元素[2]之後,手動把當前下標索引-1,以使下一次迴圈的時候,通過-1後的下標索引取出來的元素是[3],而不是略過[3]。

當然,這還不是最優解,所以,我搜索到了通用的解決方案:1、倒序迴圈遍歷;2、遍歷拷貝的list,操作原始的list。

1、倒序迴圈:

num_list = [1,5]
print(num_list)

for i in range(len(num_list)-1,-1,-1):
 if num_list[i] == 2:
  num_list.pop(i)
 else:
  print(num_list[i])

print(num_list)

執行結果完全正確。那麼,為何正序迴圈時刪除就有問題,而倒序迴圈時刪除就ok?額。。。。。。言語難表,還是畫個醜圖出來吧。

1)正序迴圈時刪除:

刪除元素[2]之後,下一次迴圈的下標索引為2,但此時,裡面存放的是[4],於是就把[3]給漏了。

2)倒序迴圈時刪除

刪除元素[2]後,[3,5]往前擠,但是沒關係,因為下一次迴圈的下標索引為0,裡面存放的是[1],所以正是我們所期望的正確的元素值。

2、遍歷拷貝的list,操作原始的list

num_list = [1,5]
print(num_list)

for item in num_list[:]:
 if item == 2:
  num_list.remove(item)
 else:
  print(item)

print(num_list)

原始的list是num_list,那麼其實,num_list[:]是對原始的num_list的一個拷貝,是一個新的list,所以,我們遍歷新的list,而刪除原始的list中的元素,則既不會引起索引溢位,最後又能夠得到想要的最終結果。此方法的缺點可能是,對於過大的list,拷貝後可能很佔記憶體。那麼對於這種情況,可以用倒序遍歷的方法來實現。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對我們的支援。