【问题标题】:Difference between normal looping of list and using slice?列表的正常循环和使用切片之间的区别?
【发布时间】:2013-11-03 03:11:46
【问题描述】:

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

首先我尝试使用普通循环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]

【问题讨论】:

  • 注意“我从切片中了解到的是它创建了一个临时列表”。并不真地!它创建一个新列表,例如,[1, 3, 6] 创建一个新列表,或创建列表的任何其他。它“临时”的唯一意义是,在您的代码中,您没有将名称绑定到它。因此,一旦 for 循环完成对切片的迭代,切片就会变成垃圾。如果你完成了,例如 temp = list2[:] 并迭代 temp,只要 temp 保持在范围内,副本就会存在。
  • 嗨,蒂姆,如果我这样做 temp = list2[:] 并迭代 temp,那么它就像我的第一个案例一样。但是,如果我循环 list2[:] 并从 list2 中删除,这意味着循环临时列表并从原始列表中删除。无论如何感谢您的评论。

标签: python list slice


【解决方案1】:

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

例如,如果您在索引 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)

【讨论】:

    【解决方案2】:

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

    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)
    

    【讨论】:

      【解决方案3】:

      在列表一中,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 而只是一个副本,因此当您删除项目时,您并没有删除您正在迭代的任何内容。

      【讨论】:

      • 啊,我明白了,我从旧列表中删除 list2 并循环浏览新列表,这就是我对切片感到困惑的地方。非常感谢。
      【解决方案4】:

      slicing operator 复制您正在操作的列表,从而获得准确的结果。

      【讨论】:

        猜你喜欢
        • 2017-05-29
        • 1970-01-01
        • 2010-09-06
        • 2011-04-07
        • 2019-03-02
        • 2018-11-05
        • 2017-01-25
        • 1970-01-01
        • 2019-01-11
        相关资源
        最近更新 更多