【问题标题】:Why wasn't the last number in that list removed?为什么该列表中的最后一个数字没有被删除?
【发布时间】:2020-03-29 20:49:16
【问题描述】:

这是我的 Python 程序:

def highest_even(li):
  for num in li:
    if num % 2 != 0:
      li.remove(num)
  return li

print(highest_even([10,2,3,4,5,80,15,99]))

输出是:

[10, 2, 4, 80, 99]

我想知道为什么99 没有被删除。

谢谢。

【问题讨论】:

  • 不要修改你迭代的列表
  • 不要同时从列表中迭代和删除
  • 您正在同时删除和迭代,这可能很棘手,不推荐。例如,当您删除 5 时,您认为列表会发生什么?
  • 删除 15 时被跳过
  • 一个很好的现有答案stackoverflow.com/a/36268815/7746992

标签: python


【解决方案1】:

修改您正在迭代的列表通常是个坏主意,可能会发生各种奇怪的事情。这里发生的特别奇怪的事情与 Python 迭代列表的方式有关。

想想 Python 保持当前项目的位置以进行迭代。当您删除一个项目时,其他项目都会在列表中“向左”移动,但 Python 仍会推进该位置。这意味着,如果您连续有两个奇数(例如 1599(a),则删除 15 会将 99 移动到左侧(移动到 @ 987654325@ 是),但下一次迭代将查看 99之前移动的位置,而不是现在的位置。

例如,考虑列表[1, 3, 6, 8],这些是 Python 将采取的步骤:

List          Pos  newList    newPos  comment
----          ---  -------    ------  -------
[1, 3, 6, 8]   0   [3, 6, 8]     1    Odd 1, delete, advance.
[3, 6, 8]      1   [3, 6, 8]     2    Even 6, leave, advance.
[3, 6, 8]      2   [3, 6, 8]     3    Even 8, leave, advance.
[3, 6, 8]      3                      iteration finished.

你可以看到连续的奇数在这里会造成问题,它只会删除交替的。

至于解决方案:如果您的 代码 建议您只想要列表中的偶数,您可以使用更简洁(和 Pythonic)的列表理解(甚至不需要执行此操作的函数):

myList = [10, 2, 3, 4, 5, 80, 15, 99]
evens = [item for item in myList if item % 2 == 0]
# gives [10, 2, 4, 80]

并且,为了完整起见,由于您的 函数名称 似乎表明您想要 最高 偶数,这将类似于:

biggestEven = max([item for item in myList if item % 2 == 0])
# gives 80

(a) 您的问题实际上与 99 位于列表的 end 的事实无关,any列表中任何位置的连续奇数都会导致相同的问题。

【讨论】:

    【解决方案2】:

    不要修改你在其中迭代的列表

    你可以在迭代之前复制

    def highest_even(li):
      for num in li.copy():
        if num % 2 != 0:
          li.remove(num)
      return li
    
    print(highest_even([10,2,3,4,5,80,15,99]))
    

    执行:

    [10, 2, 4, 80]
    

    【讨论】:

      【解决方案3】:

      正如许多 cmets 所提到的:在迭代列表时修改列表是不安全的(或者至少会出现一些意外行为)。对于不是巨大的列表,这里通常的解决方法是在您迭代列表时简单地复制列表。

      for num in li[:]:
         # everything as before
      

      这个小切片语法使 Python 获取列表 li,创建一个包含其全部内容的新列表,然后对其进行迭代。现在,由于您要从 li 中删除内容,但要遍历通过切片创建的 li 的副本,所以没有问题。

      【讨论】:

        【解决方案4】:

        这是因为您在编辑列表时对其进行了迭代。

        only_even = []
        for n in lst:
            if not n % 2:
               only_even.append(n)
        
        

        其他方法

        only_even = [n for n in lst if not n % 2]
        only_even = list(filter(lambda x: not n % 2, lst))
        

        【讨论】:

          【解决方案5】:

          您不应该更新您正在迭代的数据结构,以保持循环的不变量。

          如果你在for num in li:之后打印linum,你会看到从列表中删除元素后,下一个元素被跳过,这意味着索引向前移动, 99 元素也会发生同样的事情。

          你可以在这里查看。

          def highest_even(li):
            for num in li:
              print(li, num)
              if num % 2 != 0:
                li.remove(num)
          return li
          

          给出输出:

          In [3]: highest_even([10,2,3,4,5,80,15,99])
          ([10, 2, 3, 4, 5, 80, 15, 99], 10)
          ([10, 2, 3, 4, 5, 80, 15, 99], 2)
          ([10, 2, 3, 4, 5, 80, 15, 99], 3)
          ([10, 2, 4, 5, 80, 15, 99], 5)
          ([10, 2, 4, 80, 15, 99], 15)
          Out[3]: [10, 2, 4, 80, 99]
          

          【讨论】:

            【解决方案6】:

            您不应遍历列表并删除同一列表中的元素。 由于索引在循环中使用迭代。 0- 10 1- 2 2- 3 3- 4 4- 5 5- 80 6- 15 7- 99 当您从列表中删除元素时,它会跳过下一个元素。 在您的示例中,对于索引 0 和 1 没有任何变化。但是当 index = 3 并根据条件删除此元素时,列表将更新为[10,2,4,5,80,15,99]

            在 index =3 之后,下一个索引是 4 和 li[4] equals 5 and not 4。而且您的条件甚至没有检查元素 4。它恰好是正确的。有一些奇数而不是 4 会再次给你错误的输出。 最后一个元素 99 也是如此。由于前一个元素 15 或 index = 6 被删除,列表的长度减少了 1,并且它不会循环 index = 4,因为索引达到其更新列表的最大值为 5(删除 3,5 和 15 后)。

            【讨论】:

              【解决方案7】:

              您不应该在迭代列表时更新它。但是你可以通过倒退来让它工作,否则你会坐在树枝上砍树枝。

              li = [10,2,3,4,5,80,15,99]
              
              for i in range(len(li) - 1, -1, -1):
                  if (i%2 != 0 ):
                      del li[i]
              print(li)
              

              【讨论】:

                【解决方案8】:

                发生的情况是您在迭代列表时正在更改列表,但该列表上的迭代器不会随着您的更改而更新。 你可以试试这个:

                for i in range len(li):
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2022-01-14
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-09-22
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-12-19
                  相关资源
                  最近更新 更多