Python的list循環遍歷中,刪除數據的正確方法


在遍歷list,刪除符合條件的數據時,總是報異常,代碼如下:

 1 num_list = [1, 2, 3, 4, 5]
 2 print(num_list)
 3 
 4 for i in range(len(num_list)):
 5     if num_list[i] == 2:
 6         num_list.pop(i)
 7     else:
 8         print(num_list[i])
 9 
10 print(num_list)

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

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

修改代碼如下:

 1 num_list = [1, 2, 3, 4, 5]
 2 print(num_list)
 3 
 4 for i in range(len(num_list)):
 5     if i >= len(num_list):
 6         break
 7 
 8     if num_list[i] == 2:
 9         num_list.pop(i)
10     else:
11         print(num_list[i])
12 
13 print(num_list)

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

[1, 2, 3, 4, 5]
1
4
5
[1, 3, 4, 5]

雖然最后,list中的元素[2]確實被刪除掉了,但是,在循環中的打印結果不對,少打印了[3]。

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

再次修改代碼,結果一樣,絲毫沒有改觀:

 1 num_list = [1, 2, 3, 4, 5]
 2 print(num_list)
 3 
 4 for item in num_list:
 5     if item == 2:
 6         num_list.remove(item)
 7     else:
 8         print(item)
 9 
10 print(num_list)

找出問題的根本原因所在,想要找到正確的方法,也並不難,再次修改代碼:

 1 num_list = [1, 2, 3, 4, 5]
 2 print(num_list)
 3 
 4 i = 0
 5 while i < len(num_list):
 6     if num_list[i] == 2:
 7         num_list.pop(i)
 8         i -= 1
 9     else:
10         print(num_list[i])
11 
12     i += 1
13 
14 print(num_list)

執行結果,完全正確:

[1, 2, 3, 4, 5]
1
3
4
5
[1, 3, 4, 5]

我的做法是,既然用for循環不行,那就換個思路,用while循環來搞定。每次while循環的時候,都會去檢查list的長度(i < len(num_list)),這樣,就避免了索引溢出,然后,在符合條件,刪除元素[2]之后,

手動把當前下標索引-1,以使下一次循環的時候,通過-1后的下標索引取出來的元素是[3],而不是略過[3]。

當然,這還不是最優解,所以,我搜索到了通用的解決方案:

  1、倒序循環遍歷;

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

1、倒序循環:

 1 num_list = [1, 2, 3, 4, 5]
 2 print(num_list)
 3 
 4 for i in range(len(num_list)-1, -1, -1):
 5     if num_list[i] == 2:
 6         num_list.pop(i)
 7     else:
 8         print(num_list[i])
 9 
10 print(num_list)

執行結果完全正確

解釋正序循環時刪除就有問題,而倒序循環時刪除就ok

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

 

 2)倒序循環時刪除

刪除元素[2]后,[3, 4, 5]往前擠,但是沒關系,因為下一次循環的下標索引為0,里面存放的是[1],所以正是我們所期望的正確的元素值。

 

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

 1 num_list = [1, 2, 3, 4, 5]
 2 print(num_list)
 3 
 4 for item in num_list[:]:
 5     if item == 2:
 6         num_list.remove(item)
 7     else:
 8         print(item)
 9 
10 print(num_list)

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM