Python 在遍历列表时删除元素时出现问题

Python 在遍历列表时删除元素时出现问题,python,python-3.x,for-loop,if-statement,Python,Python 3.x,For Loop,If Statement,作为初学者,我正在编写一个简单的脚本,以便更好地熟悉python。我运行了下面的代码,但没有得到预期的输出。我认为for循环在最后一次迭代之前结束,我不知道为什么 letters = ['a', 'b', 'c', 'c', 'c'] print(letters) for item in letters: if item != 'c': print('not c') else: letters.remove(item) conti

作为初学者,我正在编写一个简单的脚本,以便更好地熟悉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”。 如果您有更好的编写代码的方法,我们也会很感激。

字母.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)
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)

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

答案#1

当您删除这样的项目时,它会更改列表的长度,因此最好向后循环。请尝试对字母[:-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']
['a', 'b']
答案#2-使用列表理解而不是循环(更多细节:):

输出:

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

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

答案#1

当您删除这样的项目时,它会更改列表的长度,因此最好向后循环。请尝试对字母[:-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']
['a', 'b']
答案#2-使用列表理解而不是循环(更多细节:):

输出:

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

这通常不是最好的方法,因为这是最坏情况下的二次时间算法thansk@juanpa.arrivillaga。就执行时间而言,这是最糟糕的情况?是的。像那样使用
.remove
效率低下,这是一个线性时间操作。在一个循环中,总的来说它变成了二次时间gotchya@juanpa.arrivillaga,我个人永远不会写这样的代码,但这是我的答案,如果不彻底修改OP的代码并帮助回答OP的具体问题。这可能只是对OP的教育,或者OP处理的是很小的列表,这些代码是可以接受的。我主要使用pandas,作为一个初学者,我习惯于循环,但我会不惜一切代价避免循环,尤其是以昂贵的方式。我会更新我的答案,让你的警告更清楚。我的观点是,如果你使用循环和列表,你仍然不会这样做。您将循环并创建一个新列表,就像您的列表理解一样。不管怎么说,避免循环并不是真正的编程最佳实践,这是pandas/numpy特有的(因为关键是在编译代码中利用内置循环)。这通常不是最好的方法,因为这是一种最坏的二次时间算法thansk@juanpa.arrivillaga。就执行时间而言,这是最糟糕的情况?是的。像那样使用
.remove
效率低下,这是一个线性时间操作。在一个循环中,总的来说它变成了二次时间gotchya@juanpa.arrivillaga,我个人永远不会写这样的代码,但这是我的答案,如果不彻底修改OP的代码并帮助回答OP的具体问题。这可能只是对OP的教育,或者OP处理的是很小的列表,这些代码是可以接受的。我主要使用pandas,作为一个初学者,我习惯于循环,但我会不惜一切代价避免循环,尤其是以昂贵的方式。我会更新我的答案,让你的警告更清楚。我的观点是,如果你使用循环和列表,你仍然不会这样做。您将循环并创建一个新列表,就像您的列表理解一样。无论如何,避免循环并不是真正的编程最佳实践,这对于pandas/numpy来说是非常特殊的(因为关键是在编译代码中利用内置循环)