0

在尝试从列表中删除所有空字符串时,我遇到了一个有趣且令人费解的情况。我第一次写了下面的代码。

lst=['###','','@@@','','$$$','','','%%%','','&&&']
print "len:",len(lst)

iteration=1
for item in lst:
    print iteration,":",lst,":",len(lst),":","'%s'"%item
    if item!='':
        pass
    else:
        lst.remove(item)
    iteration+=1

它产生以下输出:

len: 10
1 : ['###', '', '@@@', '', '$$$', '', '', '%%%', '', '&&&'] : 10 : '###'
2 : ['###', '', '@@@', '', '$$$', '', '', '%%%', '', '&&&'] : 10 : ''
3 : ['###', '@@@', '', '$$$', '', '', '%%%', '', '&&&'] : 9 : ''
4 : ['###', '@@@', '$$$', '', '', '%%%', '', '&&&'] : 8 : ''
5 : ['###', '@@@', '$$$', '', '%%%', '', '&&&'] : 7 : '%%%'
6 : ['###', '@@@', '$$$', '', '%%%', '', '&&&'] : 7 : ''

注意:代码不能正常工作。输出中有一些空字符串。后来我发现了更好的方法,例如:列表推导:[x for x in lst if x!=''] 或创建一个新列表并将非空字符串复制到其中,这恰好比上面的代码更有效,因为它不涉及每次删除元素时移动位置名单。

但是,我对上述代码的输出有一些疑问。

第一个问题是,为什么循环不运行十次(迭代次数在最左边),因为列表的原始长度是十。其次,如果您查看最右边的列,您会意识到它不会打印 print@@@字符串。它完全跳过它!我的理论是in运算符是索引的糖(最有可能),因此即使列表的长度发生变化,索引也会不断增加一。这可以解释为什么在第三次迭代中的值i是空字符串而不是@@@因为lst[2]''

使用 in 运算符时有什么需要知道的吗?

4

2 回答 2

2

任何时候你在一个循环中删除你正在迭代的东西,你都会得到这样奇怪的结果。如果你遍历一个切片[:],字符串将不再消失

for item in lst[:]:

创建一个副本以进行迭代,以便您可以在不影响迭代的情况下操作列表的元素

这篇文章描述了当您在迭代列表时修改列表时会发生什么。

于 2013-06-27T23:10:49.153 回答
0

在内部,迭代列表使用索引。每次通过循环时,该索引都会增加 1,并用于检索所需的元素。如果您在迭代时删除了一个元素,一个新元素将被“移动”到您正在查看的插槽中,然后循环的下一次迭代将查看下一个,因此首先移动的元素永远不会被查看在。

一些解决方案包括:

  • 创建一个新列表(也许使用列表推导)而不是从旧列表中删除项目。如果需要,可以使用切片分配将这个新列表分配回原始容器:lst[:] = (item for item if item != "")这是最快的,因为它避免了在删除时必须多次移动项目。
  • 使用以相反的顺序遍历列表,reversed()因此您只会“移动”您已经看到的项目。
  • 迭代列表的副本,但修改原始列表。

在您的情况下,您实际上不需要遍历列表。您只想从中删除空字符串。所以第四个选择是删除空字符串,直到不再有!

try:
     while True:
         lst.remove('')   # deletes first empty string
except ValueError:        # no more empty strings
     pass
于 2013-06-27T23:13:05.963 回答