【问题标题】:Python: List indexing for loop deletion glitchPython:循环删除故障的列表索引
【发布时间】:2015-11-10 13:17:37
【问题描述】:

这是一个很难解释的问题。我在玩 Python 的列表方法,尤其是 del 索引对象。我想创建一个简单的脚本,它会创建一个从 1 到 100 的整数列表,然后是一个 for 循环,它会从列表中删除奇数。

这是我写的脚本:

def main():
    num = list(range(1,101))
    print(num)
    for i in range(0,101):
        del num[i]
    print(num)
main()

似乎可以正常工作?我也是这么想的,直到我运行它。

我不知道为什么,但是当i 被传递给del num[i] 索引时,数字本身翻了一番。

当我运行它时,我收到了IndexError: list assignment index out of range。

当我将参数从range(0,101)更改为range(0,10)时,我发现它删除了从1到20的所有奇数。

换句话说,索引中的i 在不应该的时候翻了一番。我可以得到一些有关这方面的信息吗?

【问题讨论】:

  • 现在您学到了重要的编程课程:不要在迭代时修改它们。 :)
  • 除非你能,在诸如 go 之类的语言中:)
  • 这是我对最近一个问题的回答,可能有用:stackoverflow.com/questions/32043963/…
  • @FilipHaglund,嗯,你确定吗?什么意思?
  • 它对传递给range 的变量的副本进行操作,但由于切片是指向底层数组的指针,因此它没有按我的预期工作。我的坏:)

标签: python list for-loop indexing del


【解决方案1】:

当您删除项目时,列表的大小会减小。大约 50 次循环迭代后,列表中有大约 50 个项目,因此嵌套迭代尝试删除列表之外的内容。

这是一个模拟运行:

>>> a = [1, 2, 3, 4, 5]
>>> a
[1, 2, 3, 4, 5]
>>> del a[0]
>>> a
[2, 3, 4, 5]
>>> del a[1]
>>> a
[2, 4, 5]
>>> del a[2]
>>> a
[2, 4]
>>> del a[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range

【讨论】:

    【解决方案2】:

    当您在 for 循环中使用 del 关键字时,它会从您创建的原始 num 列表中完全删除该项目。通过这样做,您的列表的长度会随着循环中的每次迭代而变得越来越小。

    这也解释了为什么它只删除奇数,因为每次删除后索引都会向下移动,从而允许偶数从程序的裂缝中溜走:

    num = range(1, 5)  # num = [1, 2, 3, 4]
    del num[0]  # results in num = [2, 3, 4]
    del num [1]  # deletes 3, and num now = [2, 4]
    etc. for a longer loop
    

    要删除奇数,请考虑使用条件检查%2 == 0 状态和list.remove() 方法:

    num = range(1, 101)
    for i in num:
        if i % 2 != 0:
            num.remove(i)
    print(num)
    

    或者你的 main() 函数中的列表理解:

    return [x for x in num if x % 2 == 0]
    

    【讨论】:

    • 天哪,你完全正确。我认为该列表会在索引期间的某处存储已删除的值。这完全向我解释了。谢谢老兄!
    • 我的意思是我确实到了将它分成两半并让它工作的地步,但感谢你解释它为什么不工作
    • 没问题,很高兴它有帮助:)
    【解决方案3】:

    您在 0 到 101 的范围内进行迭代,并在每次迭代时从 num 中删除一项,因此 num 的长度正在减少,您最终会得到一个 IndexError.

    【讨论】:

      【解决方案4】:

      这个问题与mutating a list 非常相似,同时迭代同一个列表,通过下面的链接可以帮助你更好地理解这种情况。

      http://gsb-eng.com/why-python-list-mutation-is-not-a-good-idea/

      【讨论】:

        【解决方案5】:

        对于第二个 for 循环,您应该使用总索引的一半,因为在第 50 次迭代时,将删除 50 个元素,因此列表的总索引减少到 50 ,因此在第 51 次迭代时,它会显示超出范围的错误。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-09
          • 1970-01-01
          • 1970-01-01
          • 2015-08-12
          • 2017-01-20
          相关资源
          最近更新 更多