代码之家  ›  专栏  ›  技术社区  ›  rogeriopvl

当我在迭代列表时修改列表时,为什么python跳过元素?

  •  10
  • rogeriopvl  · 技术社区  · 16 年前

    我目前正在用Python开发一个程序,我刚注意到语言中的foreach循环有问题,或者列表结构有问题。我将给出我的问题的一个通用示例来简化,因为我在我的程序和我的通用示例上都有相同的错误行为:

    x = [1,2,2,2,2]
    
    for i in x:
        x.remove(i)
    
    print x        
    

    好吧,这里的问题很简单,我认为这段代码应该删除列表中的所有元素。好吧,问题是在它执行之后,我总是得到列表中剩下的2个元素。

    我做错什么了?感谢您的帮助。

    编辑:我不想清空列表,这只是一个例子…

    6 回复  |  直到 6 年前
        1
  •  31
  •   C. K. Young    16 年前

    在Python中,这是一个有良好文档记录的行为,您不应该修改正在迭代的列表。试试这个:

    for i in x[:]:
        x.remove(i)
    

    这个 [:] 返回的“切片” x 它正好包含它的所有元素,因此实际上是 X .

        2
  •  11
  •   Erik    16 年前

    当您删除一个元素,并且for循环进入下一个索引时,您将跳过一个元素。

    向后做。或者请说明你真正的问题。

        3
  •  4
  •   John Fouhy    16 年前

    从广义上讲,我认为当你写作时:

    for x in lst:
        # loop body goes here
    

    在引擎盖下,python正在做这样的事情:

    i = 0
    while i < len(lst):
        x = lst[i]
        # loop body goes here
        i += 1
    

    如果插入 lst.remove(x) 对于循环体,也许这样你就能知道为什么会得到你想要的结果了?

    基本上,python使用移动指针遍历列表。指针从指向第一个元素开始。然后移除第一个元素,从而使 第二 元素新的第一个元素。然后指针移动到新的第二个“先前的第三个”元素。等等。(如果使用[1,2,3,4,5]而不是[1,2,2,2,2]作为示例列表,可能会更清楚)

        4
  •  3
  •   fluffels    16 年前

    为什么不使用:

    x = []
    

    这可能是因为您更改了正在迭代的相同数组。

    如果你想用自己的方式清除阵列,试试克里斯·杰斯特·杨的回答。

        5
  •  2
  •   user1801810    8 年前

    我知道这是一篇老文章,有一个公认的答案,但对于那些可能还会出现的人…

    前面的一些答案表明,在迭代过程中更改iterable是一个坏主意。但作为强调正在发生的事情的一种方式…

    >>> x=[1,2,3,4,5]
    >>> for i in x:
    ...     print i, x.index(i)
    ...     x.remove(i)
    ...     print x
    ...
    1 0
    [2, 3, 4, 5]
    3 1
    [2, 4, 5]
    5 2
    [2, 4]
    

    希望视觉效果有助于澄清。

        6
  •  1
  •   Eryk Sun    13 年前

    我同意约翰·福伊关于休息条件的看法。正如ChrisJester Young建议的那样,遍历列表的副本对remove()方法有效。但是,如果需要pop()特定的项,那么反向迭代可以工作,正如erik所提到的,在这种情况下,操作可以就地完成。例如:

    def r_enumerate(iterable):
        """enumerator for reverse iteration of an iterable"""
        enum = enumerate(reversed(iterable))
        last = len(iterable)-1
        return ((last - i, x) for i,x in enum)
    
    x = [1,2,3,4,5]
    y = []
    for i,v in r_enumerate(x):
        if v != 3:
            y.append(x.pop(i))
        print 'i=%d, v=%d, x=%s, y=%s' %(i,v,x,y)
    


    或与XLeave:

    x = [1,2,3,4,5]
    y = []
    for i in xrange(len(x)-1,-1,-1):
        if x[i] != 3:
            y.append(x.pop(i))
        print 'i=%d, x=%s, y=%s' %(i,x,y)