2015-09-27 59 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),你就已经消除,通过将您的对象收集到一个新列表中,而不是从现有的列表中删除其他对象。但是,这一次,它将需要更多的内存空间,因为您将创建一个新的单独列表。

相关问题