我想在Python中循环遍历列表并删除特定项目。 我不想创建一个新的已接受项目列表,因为在我的完整示例中,我想对我的列表进行一系列改进。这是一个简单的例子,我尝试删除列表中小于3的所有数字。
example = [1.,2.,3.,4.,5.,6.]
for e in example:
if e < 3.:
print "Removing:", e
example.remove(e)
else:
print "Accepting:", e
print "NAIVE:", example
Removing: 1.0
Accepting: 3.0
Accepting: 4.0
Accepting: 5.0
Accepting: 6.0
NAIVE: [2.0, 3.0, 4.0, 5.0, 6.0]
失败了。我认为它失败了,因为删除列表中的项目与for循环正在运行的索引混淆,即一旦项目1.
被删除,项目2.
就位于0列表,但到那时,循环就在第1位。
我可以使用deepcopy
解决此问题,如下所示:
example = [1.,2.,3.,4.,5.,6.]
import copy
for e in copy.deepcopy(example):
if e < 3.:
print "Removing:", e
example.remove(e)
else:
print "Accepting:", e
print "DEEPCOPY:", example
Removing: 1.0
Removing: 2.0
Accepting: 3.0
Accepting: 4.0
Accepting: 5.0
Accepting: 6.0
DEEPCOPY: [3.0, 4.0, 5.0, 6.0]
这可以在这里工作,但这是一个好习惯吗?会导致其他意外错误吗?有没有更好的方法来实现这一目标?或者这种结构(循环和从列表中删除)从根本上是不健全的?
我不想制作新的已接受项目列表,因为我想逐一将一系列条件应用到我的列表中,并相应地删除项目。我不想为我申请的每个条件(可能很多)提供新的列表,而且我也不想一次性应用所有条件(因为它有助于查看有多少条件)每个标准都删除了项目等。)
答案 0 :(得分:4)
我不明白你为什么不构建一个包含你想要保留的项目的新列表,因为你似乎并不关心构建一个新列表(毕竟,这就是{{1}确实)。
所以我会这样做
copy
如果你想迭代列表并进行更改,可能会迭代索引并向后转移:
example = [f for f in example if f >= 3]
但这有点特别,除非真的有必要,否则我会避免它。
要表明您不需要愚蠢的example_1,example_2,old_example等变量,请考虑:
for i in range(len(example) - 1, -1, -1):
if example[i] < 3:
del example[i]
这是一个获取列表和测试的函数,打印带有“接受”和“拒绝”的项目,并返回包含其余项目的新列表:
# Here is a number of tests for things we want throw out
def some_really_complicated_test_on_a_number(f):
... put any kind of code here and return True if we want to
delete the number...
TESTS = (
lambda f: f < 3,
lambda f: f > 16,
lambda f: (int(f) % 2) == 1, # Integer is odd
some_really_complicated_test_on_a_number,
# etc
)
我们可以调用很多像这样的测试:
def filter_with_prints(l, test):
result = []
for f in l:
if test(f):
print("Rejecting: {}".format(f))
else:
result.append(f)
print("Accepting: {}".format(f))
return result
答案 1 :(得分:1)
你是对的,问题是你正在修改你在循环中迭代的列表。这是非常不一致的,并导致许多错误。我的问题是为什么你特别想要删除列表中的项目而不是生成符合你建议的新副本?是否有具体要求?否则,我建议制作符合您限制的列表的新副本,而不是修改输入列表。所以,修改你的代码:
STATUS = [None, 'Standby', 'Approved', 'Rejected']
STATUS.index('Standby')
这不容易出错,但你可以更加pythonic并使用列表理解:
=IF(OR(MID("$A$1",3,1)="A",MID("$A$1",3,1)="C"),1,0)
编辑:我看到您要删除项目而不是创建新列表的原因是您要多次浏览列表以过滤列表。我仍然认为,即使在这种情况下,它也更具可读性,更不容易出错,并且每次创建新列表的效率都不高。如果效率是问题并且您有非常大的列表或类似的东西,我会尝试只迭代列表一次并在同一循环中删除所有无效项。但是,如果您真的想要从列表中删除项目,您可以按照@RemcoGerlich的说法进行操作,然后按索引进行反向迭代。