关于python:迭代时修改列表

Modifying list while iterating

本问题已经有最佳答案,请猛点这里访问。
1
2
3
4
5
l  = range(100)                        
for i in l:                        
    print i,                        
    print l.pop(0),                  
    print l.pop(0)

上面的python代码给出的输出与预期的非常不同。我想循环项目,以便在循环时跳过项目。

请解释一下。


永远不要更改正在循环的容器,因为该容器上的迭代器不会被通知您的更改,而且,正如您注意到的,很可能会产生一个非常不同的循环和/或不正确的循环。在正常情况下,在容器副本上循环有帮助,但在您的情况下,很明显您不希望这样做,因为在循环的50段之后,容器将是空的,如果您再次尝试弹出,您将得到一个异常。

有什么不清楚的是,你想达到什么样的行为,如果有的话?!也许你可以用while来表达你的愿望…?

1
2
3
4
5
i = 0
while i < len(some_list):
    print i,                        
    print some_list.pop(0),                  
    print some_list.pop(0)


我以前被(别人的)"聪明"代码咬过,它试图在遍历列表时修改列表。我决定在任何情况下都不做这件事。

您可以使用slice操作符mylist[::3]跳过列表中的每三个项目。

1
2
3
mylist = [i for i in range(100)]
for i in mylist[::3]:
  print(i),

关于我的示例的其他要点与Python3.0中的新语法有关。

  • 我使用列表理解来定义mylist,因为它在python 3.0中工作(见下文)
  • print是python 3.0中的一个函数

Python 3.0 range() now behaves like xrange() used to behave, except it works with values of arbitrary size. The latter no longer exists.


一般的经验法则是,在迭代集合/数组/列表时不修改它。

使用第二个列表来存储您要操作的项,并在初始循环之后在循环中执行该逻辑。


使用while循环检查数组的真实性:

1
2
3
while array:
    value = array.pop(0)
    # do some calculation here

它应该做到没有任何错误或滑稽的行为。


试试这个。它避免了您正在迭代的事物发生变化,这通常是一种代码味道。

1
2
for i in xrange(0, 100, 3):
    print i

xrange


我想这就是你想要的:

1
2
3
4
5
6
7
8
9
10
l  = range(100)  
index = 0                      
for i in l:                        
    print i,              
    try:
        print l.pop(index+1),                  
        print l.pop(index+1)
    except:
        pass
    index += 1

当要弹出的项目数是运行时决策时,编写代码非常方便。但是它的运行效率很差,代码很难维护。


此切片语法生成列表的副本,并执行所需操作:

1
2
3
4
5
l  = range(100)  
for i in l[:]:  
    print i,  
    print l.pop(0),  
    print l.pop(0)