正常循环列表和使用切片之间的区别?

时间:2013-11-03 03:11:47

标签: python list slice

在以下两个示例中,我尝试使用两种不同类型的循环从列表中删除负元素。

首先我尝试使用普通循环for i in list,但在这种情况下,当我执行list1.remove(elm)时,列表的大小减少一个元素。因此,在下一个循环中,第二个元素移动到第一个元素位置。因此,在下一个循环中测试if elm < 0时会遗漏第二个元素。因此,它不会从列表中删除所有负面元素。

其次,我尝试使用切片。我从切片中理解的是它创建了一个临时列表。所以,当我for i in list2[:]时,它会创建一个新的临时list2 = [-1,3,-2,-5,4,7,8],但我仍然没有得到清晰的图片,它是如何工作的。它删除了所有的负面因素。

#!/usr/env/bin
# remove all the negative value from the list.
list1 = [-1,3,-2,-5,4,7,8]
list2 = [-1,3,-2,-5,4,7,8]

# Looping through the list.
for elm in list1:
    if elm < 0:
        list1.remove(elm)
print 'list1: ', list1

# Looping through the list using slice.
for elm in list2[:]:
    if elm < 0:
        list2.remove(elm)
print 'list2: ', list2

Output:-python slice.py
list1: [3, -5, 4, 7, 8]
list2: [3, 4, 7, 8]

4 个答案:

答案 0 :(得分:4)

问题是迭代列表并同时修改它会产生一些不好的结果。

例如,如果您在索引2处,并在那里删除负数,则索引3处的值将移至索引2.在下一次迭代中,您将转到索引3,但跳过旧值指数3(新指数2)。

切片会创建一个副本,因此即使删除底片也不会受到影响。

仅供参考,另一种可能性是

filter(lambda x: x >= 0, list2)

[x for x in list2 if x >= 0]

编辑:

以下是迭代。

(index)        list1            elem
   0      [-1,3,-2,-5,4,7,8]     -1
   1      [3,-2,-5,4,7,8]        -2
   2      [3,-5,4,7,8]            4
   3      [3,4,7,8]               8

你是否看到我们错过了几个值,因为我们正在迭代并修改同样的事情?

现在使用创建副本的切片

(index)        (copy)             list2            elem
   0     [-1,3,-2,-5,4,7,8]  [-1,3,-2,-5,4,7,8]     -1
   1     [-1,3,-2,-5,4,7,8]  [3,-2,-5,4,7,8]         3
   2     [-1,3,-2,-5,4,7,8]  [3,-2,-5,4,7,8]        -2
   3     [-1,3,-2,-5,4,7,8]  [3,-5,4,7,8]           -5
   4     [-1,3,-2,-5,4,7,8]  [3,4,7,8]               4
   5     [-1,3,-2,-5,4,7,8]  [3,4,7,8]               7
   6     [-1,3,-2,-5,4,7,8]  [3,4,7,8]               8

我们遍历所有七个值,而不跳过任何值。

仅供参考,list2[:]相当于list2[0:len(list2):1]list(list2)

答案 1 :(得分:1)

我会在这里使用列表理解来创建一个包含您要保留的元素的新列表:

numbers = [-1, 3, -2, -5, 4, 7, 8]
positive = [n for n in numbers if n >= 0]

或通过切片分配将新序列重新分配到现有序列中:

numbers = [-1, 3, -2, -5, 4, 7, 8]
numbers[:] = (n for n in numbers if n >= 0)

答案 2 :(得分:1)

在第一个列表中,python正在迭代一个项目,这会导致意外的结果,如您所见。观看:

for elm in list1:
    if elm < 0:
        list1.remove(elm)
    print list1

这将打印:

[3, -2, -5, 4, 7, 8]
[3, -5, 4, 7, 8]
[3, -5, 4, 7, 8]
[3, -5, 4, 7, 8]
[3, -5, 4, 7, 8]

因此,当你删除一个项目后python返回for elm in list1时,它将不会转到那之后的那个,而是之前的那个(3)。因此循环。

当你复制list2[:]时,你实际上并没有迭代list2而只是一个副本,因此当你删除项目时,你不会删除任何你正在迭代的内容

答案 3 :(得分:0)

切片操作员会复制您正在操作的列表,从而获得准确的结果。