Python:难以过滤掉包含某些子字符串的字符串

时间:2015-09-27 05:14:22

标签: python list

我有一个我想要过滤的字符串列表。如果它包含单词blahblah,那么我想保留它。我尝试了第一种方式,并且我一遍又一遍地使用了我的代码,但我不知道为什么它会保留一些字符串,其中没有“blahblah”这个词。但是,我尝试了第二种方式,它起作用了。我很好奇为什么第一种方法不起作用。

第一种方法:

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. 如果我使用第二种方法,如果我有一个非常大的列表,我的代码会运行得更慢吗?

2 个答案:

答案 0 :(得分: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)时运行得更快,您可以通过在新列表中收集对象而不是从现有列表中删除其他对象来消除它。但是,这一次,它将需要更多的内存空间,因为您将创建一个新的单独列表。

答案 1 :(得分:5)

回答第一个问题,因为当迭代列表时,内部Python会跟踪当前迭代所达到的索引,当你从列表中删除项目时,它会移动元素的索引,之后删除元素,向左移动1(将这些索引减1),因此在下一次迭代中,您可能最终跳过一个元素(因为这种移动)。

要回答第二个问题,它应该比删除方法更快,因为.remove()是一个O(n)操作,它需要找到要删除的元素然后将其删除,与此相比,{{ 1}}会更快。

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

.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']