缩短循环中期的长度

时间:2017-06-25 20:52:29

标签: python python-2.7 loops

我有这段代码:

numbers = [0,1,2,3,4]

for i in range(0,len(numbers),1):
    print 'i = {} , len(numbers) = {}'.format(i,len(numbers))
    numbers.remove(i)

输出结果为:

i = 0 , len(numbers) = 5
i = 1 , len(numbers) = 4
i = 2 , len(numbers) = 3
i = 3 , len(numbers) = 2
i = 4 , len(numbers) = 1

我的问题是,为什么循环停止运行一次' i'比那更大(数字)'? (第4行)

谢谢

1 个答案:

答案 0 :(得分:1)

列表的长度与此无关。要了解原因,请继续阅读。

首先,您误解了range函数的作用。来自文档:

  

范围(开始,停止[,步骤])这是一个多功能的创建功能   包含算术进度的列表。它最常用于   环路。

range做的是创建一个(有些)数字列表( python2 ),然后迭代它。

>>> range(0, 5, 1)
[0, 1, 2, 3, 4]

这可能看起来一样,但事实上,它是一个完全不同的列表。您可以通过将返回值分配给变量,然后打印出id(),然后numbers来确认。

您要做的是迭代实际列表,而不是range函数生成的列表。您可以通过稍微更改循环定义来执行此操作:

numbers = [0, 1, 2, 3, 4]

ctr = 0
for i in numbers:
    print('i = {} , len(numbers) = {}'.format(ctr, len(numbers)))
    numbers.remove(i)
    ctr += 1

输出:

i = 0 , len(numbers) = 5
i = 1 , len(numbers) = 4
i = 2 , len(numbers) = 3

现在,您会看到,在每次迭代后,列表会变短,直到列表在i命中之前耗尽。

要明白原因,就会发生这样的事情:

Iteration 0
    0   1   2   3   4    (numbers)
   ctr

Iteration 1 (0 deleted)
    1   2   3   4        (numbers)
      ctr

Iteration 2 (1 deleted)
    2   3   4            (numbers)
           ctr

End (2 deleted)

这里,ctr就像一个指针,指向列表中的当前元素。循环的每次迭代ctr都会向前推进一步到下一个元素。

现在,每次删除元素时,不仅列表大小缩小,而且迭代器前进一个步骤,因此您实际上向前移动两次

我们如何防止这种情况?你已经发现了解决方案。使用range

numbers = [0, 1, 2, 3, 4]

ctr = 0
for i in range(0, len(numbers), 1):
    print('i = {} , len(numbers) = {}'.format(ctr, len(numbers)))
    numbers.remove(i)
    ctr += 1

这就是:

Iteration 0 
    0   1   2   3   4   (numbers)
    0   1   2   3   4   (range)
    ctr


Iteration 1 (0 deleted)
    1   2   3   4       (numbers)
    0   1   2   3   4   (range)
        ctr

Iteration 2 (1 deleted)
    2   3   4           (numbers)
    0   1   2   3   4   (range)
           ctr

Iteration 3 (2 deleted)
    3   4               (numbers)
    0   1   2   3   4   (range)
               ctr

Iteration 4 (3 deleted)
    4                   (numbers)
    0   1   2   3   4   (range)
                   ctr

End (4 deleted) 

所以,你得到:

i = 0 , len(numbers) = 5
i = 1 , len(numbers) = 4
i = 2 , len(numbers) = 3
i = 3 , len(numbers) = 2
i = 4 , len(numbers) = 1

TL; DR

总而言之,当您遍历副本时,原始列表将缩小,这意味着长度也会减少,但是因为您正在迭代range对象,该对象返回0到4之间的数字序列(包括0和4)并且不受后续删除的影响,循环将运行5次迭代(等于range返回的元素数)。