首页 > 解决方案 > 如何在python中没有列表理解的情况下使用for循环从列表中弹出所有负数

问题描述

我收到一条错误消息,说“Traceback(最近一次调用最后一次):文件“main.py”,第 10 行,如果 list1[j] < 0:IndexError:列表索引超出范围”

我正在尝试从样本输入“10 -7 4 39 -6 12 2”中删除所有负数,以制作像 10 4 39 12 2 这样的输出,尝试使用 pop 来执行此操作。

我无法找到一个确切的解决方法,我通过谷歌搜索并在stackoverflow上搜索。

我不希望列表理解作为答案

input1 = str(input())

list1 = input1.split()

for i in range(len(list1)):
    list1[i] = int(list1[i])


for j in range(len(list1)):
        if list1[j] < 0:
            list1.pop(j)

print(list1)

标签: pythonfor-loop

解决方案


你为什么要使用pop?由于您没有保存该值,因此您可能应该使用del list1[index].

在任何情况下,在迭代时修改列表都是 1) 正确执行令人讨厌 2) 效率非常低。相反,您应该使用列表理解或常规循环创建一个新列表。

根本问题是,当您删除一个项目时,之后的所有索引都已移动

天真地,您可能认为您可以执行以下操作:

for i, e in enumerate(data):
    if e < 0:
        del data[i]

这不会引发索引错误,但是,如果您有两个相邻的负数,它将跳过一个:

>>> data = [1,2, -3, -4, 5]
>>> for i,e in enumerate(data):
...     if e < 0:
...         del data[i]
...
>>> data
[1, 2, -4, 5]
>>>

但是这里有几种方法可以做到。

请记住,这些算法效率低下

首先,只需跟踪您已删除的项目数量并相应地调整索引:

>>> removed = 0
>>> data = [1,2, -3, -4, 5]
>>> for i in range(len(data)):
...     if data[i - removed] < 0:
...         del data[i - removed]
...         removed += 1
...
>>> data
[1, 2, 5]

也许最简单的方法是使用一个while循环,实际上:

>>> data = [1,2, -3, -4, 5]
>>> i = 0
>>> while i < len(data):
...     if data[i] < 0:
...         del data[i]
...     else:
...         i += 1
...
>>> data
[1, 2, 5]

i上面的重点是仅在您不删除某些内容时才增加。

最后,您可以简单地从列表末尾开始迭代:

>>> data = [1,2, -3, -4, 5]
>>> for i in reversed(range(len(data))):
...     if data[i] < 0:
...         del data[i]
...
>>> data
[1, 2, 5]
>>>

重申:

上述算法都是非常低效的。

它们需要线性空间和二次时间。您可以在线性空间和线性时间中创建一个新列表。

考虑:

>>> data = [1,2, -3, -4, 5]
>>> new_data = []
>>> for x in data:
...     if x >= 0:
...         new_data.append(x)
...
>>> new_data
[1, 2, 5]

或等效的列表理解:

>>> data = [x for x in data if x >= 0]
>>> data
[1, 2, 5]

推荐阅读