在Python中循环列表并删除条目

2024-05-19 03:02:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我想在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]

这在这里管用,但这是好的做法吗?会导致其他意外的错误吗?有没有更好的方法来实现这一点?或者这种构造(循环并从列表中删除)根本上不健全?你知道吗

我不想建立一个接受项目的新列表,因为我想对我的列表逐一应用一系列条件,并相应地删除项目。我不想为我应用的每个标准都列出一个新的列表(可能是多个),也不想一次性应用所有标准(因为查看每个标准删除了多少项很有帮助)。你知道吗


Tags: in列表for标准ifexampleelseremove
2条回答

你是对的,问题是你在修改循环中遍历的列表。这是非常不一致的,并导致许多错误。我的问题是,为什么你特别有兴趣删除列表中的项目,而不是生成一个符合你建议的新副本?有没有具体要求?否则,我建议创建一个满足您的限制的列表的新副本,而不是修改输入列表。因此,修改代码:

example = [1.,2.,3.,4.,5.,6.]
new_list = []
for e in example:
   if e >= 3.:
      new_list.append(e)
      print "Accepting:", e
   else:
      print "Removing: ", e

这不太容易出错,但您可以更通情达理地使用列表理解:

new_list = [e for e in example if e >= 3.]

编辑:我发现您想要删除项目而不是创建新列表的原因是您要对列表进行多次筛选。我仍然认为,即使在这种情况下,每次创建一个新列表的可读性更高,更不容易出错,效率也不会特别低。如果效率是个问题,并且您有非常大的列表或类似的东西,我将尝试只遍历列表一次,并在同一个循环中删除所有无效项。但是,如果你真的想从列表中删除项目,你可以按照@RemcoGerlich所说的做,然后按索引反向迭代。你知道吗

我不明白你为什么不用你想要保留的项目来构建一个新的列表,因为你似乎并不关心构建一个新的列表(毕竟,copy就是这么做的)。你知道吗

所以我就这么做

example = [f for f in example if f >= 3]

如果您确实想迭代列表并更改它,可以迭代索引并向后返回

for i in range(len(example) - 1, -1, -1):
    if example[i] < 3:
        del example[i]

但这有点特别,除非真的有必要,否则我会避免。你知道吗

要表明您不需要愚蠢的示例1、示例2、旧的示例等变量,请考虑:

# 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
)

下面是一个函数,它接受一个列表和一个测试,打印带有“accepting”和“rejecting”的项,并返回一个带有剩余项的新列表:

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

我们可以这样称呼很多测试:

example = [1., 2., 3., 4., 5., 6.]

for test in TESTS:
    example = filter_with_prints(example, test)

相关问题 更多 >

    热门问题