如何从循环中的python列表中移除项?

How to remove item from a python list in a loop?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Remove items from a list while iterating in Python

我正在尝试从python中的列表中删除一个项目:

1
2
3
4
5
x = ["ok","jj","uy","poooo","fren"]
for item in x:
    if len(item) != 2:
        print"length of %s is: %s" %(item, len(item))
        x.remove(item)

但它没有删除"fren"项。有什么想法吗?


迭代列表时不能从列表中删除项。基于旧列表构建新列表要容易得多:

1
y = [s for s in x if len(s) == 2]


海姆洛特和斯文的答案有效,但他们不修改列表(创建一个新的列表)。如果需要修改对象,则需要指定给切片:

1
x[:] = [value for value in x if len(value)==2]

但是,对于需要删除少数元素的大型列表,这是一种内存消耗,但它在O(N)中运行。

glglgl的答案有O(n2)复杂性,因为list.remove是O(n)。

根据数据的结构,您可能更喜欢记下要删除的元素的索引,并使用del键按索引删除:

1
2
3
to_remove = [i for i, val in enumerate(x) if len(val)==2]
for index in reversed(to_remove): # start at the end to avoid recomputing offsets
    del x[index]

现在,del x[i]也是O(n),因为您需要在索引i之后复制所有元素(列表是一个向量),所以您需要对数据进行测试。不过,这应该比使用remove更快,因为您不需要支付删除的搜索步骤的成本,而且在这两种情况下复制步骤的成本是相同的。

[编辑]位置非常好,O(N)版本内存需求有限,由@sven marnach提供。它使用了Python2.7中引入的itertools.compress

1
2
3
4
5
6
from itertools import compress

selectors = (len(s) == 2 for s in x)
for i, s in enumerate(compress(x, selectors)): # enumerate elements of length 2
    x[i] = s # move found element to beginning of the list, without resizing
del x[i+1:]  # trim the end of the list


1
x = [i for i in x if len(i)==2]

前面提到的列表理解方法可能是您最好的选择。但是,如果您绝对想在适当的地方进行(例如,如果x非常大),可以使用以下方法:

1
2
3
4
5
6
7
8
x = ["ok","jj","uy","poooo","fren"]
index=0
while index < len(x):
    if len(x[index]) != 2:
        print"length of %s is: %s" %(x[index], len(x[index]))
        del x[index]
        continue
    index+=1

这源于这样一个事实:在删除时,迭代跳过一个元素,因为它semms只处理索引。

解决方法可能是:

1
2
3
4
5
x = ["ok","jj","uy","poooo","fren"]
for item in x[:]: # make a copy of x
    if len(item) != 2:
        print"length of %s is: %s" %(item, len(item))
        x.remove(item)