我们正在谈论删除给定值的每次出现。list.remove
已经进行了扫描,所以我们可以在知道它是否成功之前调用它:
for sublist in dataSet:
while True: # list.remove only removes the first occurence
try:
sublist.remove("311472")
except ValueError, e:
break # stop removing, there's no such item in this sublist
如果确实包含删除值的列表很大,这自然不是很有效,因为我们重复了删除。对于 Martijn Pieters 建议的列表理解解决方案,瓶颈在于不包含已删除值的列表是否很大(因为它们已被重建)。
第三种解决方案是扫描列表并移动条目,将条目的释放保存到末尾:
def removeAll(lst, item):
"Like list.remove(), but removes all matching items, without raising ValueError"
outend=0
instart=0
while True:
try:
inend=lst.index(item, instart)
except ValueError, e:
# We've reached the end of the list
if outend!=instart:
# Place remaining items in the correct place and truncate
lst[outend:]=lst[instart:]
return
size=inend-instart
# Move non-matching items down to replace matching ones
if size and outend!=instart:
lst[outend:outend+size]=lst[instart:inend]
outend+=size
instart=inend+1 # Skip over the matching entry
过早优化的非常可怕的例子 - 这需要太长时间来编写和调试,并且与普通重建相比只有边际收益(可能根本没有,取决于程序的其余部分)。实际上,仔细想想,我认为没有任何好处,因为列表切片本身会创建我们想要保留的部分的子副本。我想它会做到这一点,您要删除的元素比例很高,列表很长,并且真的希望就地完成更改。重建解决方案后更改原始列表很简单:
lst[:]=[item for item in lst if item!=key]
实际上,这足以让我编写另一个就地删除变体。这是一个更 Pythonic,但仍然很浪费的变体:
def removeAll2(lst, remove):
rem=0
for idx,value in enumerate(lst):
if value==remove:
rem+=1
elif rem:
lst[idx-rem]=value
if rem:
del lst[-rem:]
没有例外,只有一个通过列表,但一些笨拙的索引计算。不过,这可能与内存效率一样高。