我尝试了下面的代码来从列表中删除元素:
x = ["ok", "jj", "uy", "poooo", "fren"]
for item in x:
if len(item) != 2:
x.remove(item)
为什么x
中的"fren"
没有被移除?
在迭代列表时不能删除其中的项。更简单的方法是基于旧列表构建一个新列表:
y = [s for s in x if len(s) == 2]
hymloth和sven的答案是正确的,但它们并没有修改列表(它们创建了一个新列表)。如果你需要修改对象,你需要分配给一个切片:
x[:] = [value for value in x if len(value)==2]
然而,对于需要删除少量元素的大型列表,这样做会消耗大量内存,但其时间复杂度为O(n)。
glglgl的答案受到O(n²)的复杂度影响,因为list.remove
是O(n)的。
根据您的数据结构不同,您可以选择记录要删除元素的索引,并使用del
关键字按索引进行删除:
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),因为你需要复制索引之后的所有元素(列表是一个向量),所以你需要根据你的数据测试这个。尽管如此,这应该比使用remove
更快,因为你不需要为删除操作中的搜索步骤付出代价,并且在两种情况下,复制步骤的成本是相同的。[编辑]非常好的就地、O(n)版本,具有有限的内存要求,由@Sven Marnach提供。它使用了在python 2.7中引入的itertools.compress
:
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
x[:]
而不是 x
呢? - Kirk Strauserx = [i for i in x if len(i)==2]
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)
已经提到过的列表推导式方法可能是你的最佳选择。但如果你绝对想要在原地完成它(例如如果x
非常大),这里有一种方法:
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