2015-09-27 92 views
3

我有我想要過濾的字符串列表。如果它包含單詞blahblah,那麼我想保留它。我嘗試了第一種方法,並且一遍又一遍地檢查了我的代碼,但我不知道爲什麼它保留了一些沒有「blahblah」單詞的字符串。但是,我嘗試了第二種方式,它工作。我很好奇爲什麼第一種方式不起作用。Python:難以濾除包含某些子字符串的字符串

第一種方法:

for item in my_list: 
    if 'blahblah' not in item: 
     my_list.remove(item) 

第二種方法:

my_new_list = [] 
for m in my_list: 
    if 'blahblah' in m: 
     my_new_list.append(p) 

第二種方法給我我想要的。我精心檢查了第二個列表中生成的列表中的每一個元素。

  1. 爲什麼第一種方法無法正常工作?
  2. 如果我使用第二種方法,如果我有一個非常大的列表,我的代碼是否會運行得更慢?

回答

5

要遍歷列表時,回答的第一個問題,其原因,內部的Python跟蹤在其當前迭代已經達到了,當你從列表中刪除項目的索引,它改變了元素的索引,後將被移除的元素向左移1(將這些索引減1),因此在下一次迭代中,最終可能會跳過一個元素(因爲這種移位)。


爲了回答第二個問題,它應該比去除方法更快,因爲.remove()是O(n)的操作,其中它需要找到刪除,然後將其刪除的元件,相比,.append()將快點。

更快一點的方法是使用列表理解 -

my_new_list = [m for m in my_list if 'blahblah' in m] 

如果你想改變my_list的地方,你可以在任務的左側使用[:] -

my_list[:] = [m for m in my_list if 'blahblah' in m] 

演示 -

>>> my_list = ['blahblah','asdas'] 
>>> [m for m in my_list if 'blahblah' in m] 
['blahblah'] 

時序比較EEN兩種方法(如在意見中的要求) -

In [4]: def func1(): 
    ...:  my_list = ['blahblah' for _ in range(100)] 
    ...:  my_list[:] = [m for m in my_list if 'blahblah' in m] 
    ...: 

In [5]: def func2(): 
    ...:  my_list = ['blahblah' for _ in range(100)] 
    ...:  new_list = [m for m in my_list if 'blahblah' in m] 
    ...: 

In [6]: %timeit func1() 
100000 loops, best of 3: 13.9 µs per loop 

In [7]: %timeit func2() 
100000 loops, best of 3: 13.2 µs per loop 

In [8]: %timeit func1() 
100000 loops, best of 3: 13.9 µs per loop 

In [9]: %timeit func2() 
100000 loops, best of 3: 13.2 µs per loop 

In [10]: %timeit func1() 
100000 loops, best of 3: 13.8 µs per loop 

In [11]: %timeit func2() 
100000 loops, best of 3: 13.3 µs per loop 
+0

關於名單的理解,有沒有在速度上的差異,如果我改變它在的地方,而不是建立新的名單? – AlanH

+0

我不確定,需要測試,但我想就地可能會比簡單地綁定到一個新名稱慢一點。 –

+0

@AlanH我添加了時間比較,綁定到新名稱比位置更改要快一些。 –

5

你不應該修改列表,而是迭代它,因爲你將失去元素的實際位置。您可以使用列表內涵做過濾:

my_list[:] = [s for s in my_list if 'blahblah' in s] 

[:]使我們能夠就地改造,而不是首先創建一個新的過濾列表和分配回my_list的。

如果你想固守傳統for,你可以做到以下幾點:

for item in my_list[:]: 
    if 'blahblah' not in item: 
     my_list.remove(item) 

關於你的第二個問題,你的代碼可能運行速度更快的.remove()需要O(n),你就已經消除,通過將您的對象收集到一個新列表中,而不是從現有的列表中刪除其他對象。但是,這一次,它將需要更多的內存空間,因爲您將創建一個新的單獨列表。

相關問題