文章目錄
-
- 從後向前遍曆並刪除元素
-
- 使用列表解析(list comprehension)
-
- 使用filter
-
- 使用itertools模組
- Manual Loop and remove
- 效能
- reference
當我們想要在遍曆一個list的同時去刪除元素的時候,可能會遇到一些問題。先看一下下面的代碼
my_list = [1, 2, 4, 5]for elem in my_list: if elem % 2 == 0: my_list.remove(elem)print my_list
我們肯定會希望這段代碼的輸出是[1, 5 ],但事實上,是[1, 4, 5]。猜測可能的原因是遍曆my_list時,for迴圈建立的iter的內部儲存了一個index,當遍曆到2時,index = 1,而當刪除2後,下一個index = 2,而此時my_list只剩下3個元素[1, 4, 5],此時的my_list[2] = 5,所以5 % 2 != 0。跳過了4這個元素。我們可以用如下的方法來解決這個問題。
從後向前遍曆並刪除元素my_list = [1, 2, 4, 5]for i in range(len(my_list) - 1, -1, -1): if my_list[i] % 2 == 0: my_list.remove(my_list[i])print my_list
這裡我們從後向前遍曆,並且使用下標來遍曆整個list。
使用列表解析(list comprehension) my_list = [1, 2, 4, 5] print [elem for elem in my_list if elem % 2 != 0]
使用列表解析的代碼異常簡單,這裡有個區別就是我們建立了一個新的列表,不過這通常也是python裡面常用的方式。
使用filterprint filter(lambda x: x % 2, [1, 2, 4, 5])
使用filter與用列表解析類似,同樣是建立一個新列表,也是一行就完成了任務。
使用itertools模組 import itertools print [elem for elem in itertools.ifilter(lambda x: x%2, [1, 2, 4, 5])] print [elem for elem in itertools.ifilterfalse(lambda x: x%2 == 0, [1, 2, 4, 5])]
ifilter*返回一個generator用於迭代整個list
Manual Loop and removemy_list = [1, 2, 4, 5]# in place removedest = 0for i in range(len(my_list)): if my_list[i] % 2 != 0: if my_list[i] != my_list[dest]: my_list[dest] = my_list[i] dest += 1# all elements in [0, dest) is odd# so we remove all the elements in [dest, len(my_list))del my_list[dest:len(my_list)]print my_list
效能不同的方法效率不同,我們簡單地進行一下測試,對一個隨機產生的具有10000個元素的列表刪除其中的偶數,迭代100次測試其不同方法的效能。
測試使用的是CPython 2.6.4,Windows 7,CPU Phenom II 945,memory 4G。
| Method |
Time(s) |
| 從後向前遍曆並刪除元素 |
6.537 |
| 使用列表解析(list comprehension) |
0.205 |
| 使用filter |
0.203 |
| 使用itertools模組 |
0.210 |
| Manual Loop and remove |
0.227 |
我們可以看到,使用列表解析和filter,itertools方法的效能遠超過從後向前遍曆的方法。並且Manual Loop and remove的效率也沒想象中的高。可以看到使用已有的功能可以輕鬆獲得非常高的效率。
reference
http://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating-in-python