【问题标题】:Problems removing element while iterating over list [duplicate]迭代列表时删除元素的问题[重复]
【发布时间】:2020-07-15 00:24:55
【问题描述】:

作为初学者,我正在编写一个简单的脚本来更好地熟悉 python。我运行了下面的代码,但没有得到预期的输出。我认为 for 循环在最后一次迭代之前结束,我不知道为什么。

letters = ['a', 'b', 'c', 'c', 'c'] 
print(letters)
for item in letters:
    if item != 'c':
        print('not c')
    else:
        letters.remove(item)
        continue
print(letters)

输出返回:

['a', 'b', 'c', 'c', 'c'] 
not c 
not c
['a', 'b', 'c']

预期输出:

['a', 'b', 'c', 'c', 'c'] 
not c 
not c
['a', 'b']

基本上,我不再期望在我的列表中包含“c”。 如果您有更好的方法来编写代码,也将不胜感激。

【问题讨论】:

    标签: python python-3.x for-loop if-statement


    【解决方案1】:

    警告:这是一个低效的解决方案,我将提供它来回答您的问题。我将在答案 #2 中发布更简洁、更快捷的解决方案。

    答案#1

    当你删除这样的项目时,它会改变列表的长度,所以最好向后循环。尝试for item in letters[::-1] 反转列表:

    letters = ['a', 'b', 'c', 'c', 'c'] 
    print(letters)
    for item in letters[::-1]:
        if item != 'c':
            print('not c')
        else:
            letters.remove(item)
            continue
    print(letters)
    

    输出:

    ['a', 'b', 'c', 'c', 'c']
    not c
    not c
    ['a', 'b']
    

    答案 #2 - 使用列表推导而不是循环(更多细节:Is there a simple way to delete a list element by value?):

    letters = ['a', 'b', 'c', 'c', 'c']
    letters = [x for x in letters if x != 'c']
    

    输出:

    ['a', 'b']
    

    【讨论】:

    • 这通常不是首选的方法,因为这是最坏情况的二次时间算法
    • 谢谢@juanpa.arrivillaga。就执行时间而言,这是最坏的情况?
    • 是的。像这样使用.remove 是低效的,它是线性时间操作。在一个循环中,它整体变成二次时间
    • gotchya @juanpa.arrivillaga ,我永远不会亲自编写这样的代码,但这是我的答案,没有彻底检查 OP 的代码并帮助回答 OP 的具体问题。这可能只是对 OP 的教育,或者 OP 正在处理可以接受此代码的小列表。我主要使用 pandas 并且曾经作为初学者循环使用,但尽量避免循环,特别是以昂贵的方式。我将更新我的答案以阐明您的警告。
    • 我的意思是,如果您使用循环和列表您仍然不会这样做。您将循环并创建一个新列表,就像您的列表理解一样。无论如何,避免循环并不是真正的编程最佳实践,这对 pandas/numpy 来说是特定的(因为重点是在编译代码中利用 built-in 循环)
    【解决方案2】:

    letters.remove(item) 仅删除元素的单个实例,但会在您迭代列表时无意中减小列表的大小。这是您通常要避免做的事情,修改您正在迭代的相同元素。结果列表变得更短并且迭代器认为您已经遍历了所有元素,即使最后一个“c”仍在列表中。这可以从以下输出中看出:

    letters = ['a', 'b', 'c', 'c', 'c'] 
    print(letters)
    for idx,item in enumerate(letters):
        print("Index: {} Len: {}".format(idx,len(letters)))
        if item != 'c':
            print('not c')
        else:
            letters.remove(item)
            continue
    print(letters)
    
    """Index: 0 Len: 5
    not c
    Index: 1 Len: 5
    not c
    Index: 2 Len: 5
    Index: 3 Len: 4"""
    

    您永远不会遍历最后一个元素,因为索引 (4) 会超过列表的可索引元素(现在是 0-3)!

    如果要过滤列表,可以使用内置的filter 函数:

    filter(lambda x: x!='c', letters)
    

    【讨论】:

      猜你喜欢
      • 2013-01-23
      • 2011-04-02
      • 1970-01-01
      • 2018-07-18
      • 2016-12-03
      • 2010-11-09
      • 1970-01-01
      • 2016-11-21
      • 1970-01-01
      相关资源
      最近更新 更多