迭代时从Python列表中删除项目[重复]

Posted

技术标签:

【中文标题】迭代时从Python列表中删除项目[重复]【英文标题】:Delete item from list in Python while iterating over it [duplicate] 【发布时间】:2011-11-26 06:01:34 【问题描述】:

我正在为锦标赛应用程序编写循环算法。

当玩家数量为奇数时,我将'DELETE'添加到玩家列表中,但后来,当我想从日程列表中删除包含'DELETE'的所有项目时,我不能 - 一个总是左边。请看一下代码——问题很简单,我想是关于列表的;我就是看不到。

"""
Round-robin tournament:
1, 2, 3, 4, | 5, 6, 7, 8    =>  1, 2, 3, 4  => rotate all but 1 =>  1, 5, 2, 3  => repeat =>    1, 6, 5, 2  ...
                    5, 6, 7, 8              6, 7, 8, 4          7, 8, 4, 3
in every round pick l1[0] and l2[0] as first couple, after that l1[1] and l2[1]...
"""

import math

lst = []
schedule = []
delLater = False

for i in range(3):                  #make list of numbers
    lst.append(i+1)

if len(lst) % 2 != 0:               #if num of items is odd, add 'DELETE'
    lst.append('DELETE')
    delLater = True


while len(schedule) < math.factorial(len(lst))/(2*math.factorial(len(lst) - 2)): #!(n)/!(n-k)

    mid = len(lst)/2

    l1 = lst[:mid]
    l2 = lst[mid:]

    for i in range(len(l1)):            
        schedule.append((l1[i], l2[i]))         #add lst items in schedule

    l1.insert(1, l2[0])             #rotate lst
    l2.append(l1[-1])
    lst = l1[:-1] + l2[1:]


if delLater == True:                #PROBLEM!!! One DELETE always left in list
    for x in schedule:
        if 'DELETE' in x:
            schedule.remove(x)

i = 1
for x in schedule:
    print i, x
    i+=1

【问题讨论】:

【参考方案1】:
schedule[:] = [x for x in schedule if 'DELETE' not in x]

查看关于deleting from a list while iterating over it的其他问题。

【讨论】:

+1 用于使用 [:] 来修改同一个列表对象。 为什么要使用就地分配? @Macke 可能没有任何好处。它短暂地节省了一点内存,而且速度有点慢。很可能都不重要。 @agf:只是为了尽可能少地修改现有代码。就个人而言,我只会在任何地方都使用生成器,或者编写一个不需要虚假条目的算法,但这不是问题。 @agf 可读性。引入另一个列表对象会引入另一个变量,以便在阅读代码时记住。 @Velociraptors 对象身份有什么关系?您仍然可以使用相同的名称,不需要新变量:schedule = [x for x in schedule if 'DELETE' not in x]【参考方案2】:

要在迭代列表时从列表中删除元素,您需要倒退:

if delLater == True:
    for x in schedule[-1::-1]):
        if 'DELETE' in x:
            schedule.remove(x)

更好的选择是使用列表理解:

schedule[:] = [item for item in schedule if item != 'DELETE']

现在,您可以只使用 schedule = 而不是 schedule[:] = -- 有什么区别?一个例子是这样的:

schedule = [some list stuff here]  # first time creating
modify_schedule(schedule, new_players='...') # does validation, etc.

def modify_schedule(sched, new_players):
    # validate, validate, hallucinate, illustrate...
    sched = [changes here]

此时,modify_schedule 所做的所有更改都已丢失。为什么?因为它没有就地修改列表对象,而是将名称 sched 重新绑定到一个新列表,而原始列表仍然绑定到调用者中的名称 schedule

因此,您是否使用list_object[:] = 取决于您是否希望绑定到您的列表的任何其他名称来查看更改。

【讨论】:

在正确的设计中,def 返回分配回schedulesched,或者在被认为是错误的形式但合乎逻辑的设计中,您没有通过时间表你使用global schedule。无论您是否使用就地分配,上面的示例设计都是错误的,因为不清楚schedschedule 在您更改schedule 时指的是同一件事. 另外,你试过你的循环版本吗?我不确定它应该如何工作,但它至少有几个错误。您正在尝试删除列表中您不知道的内容(来自enumerate 的索引),并且您的切片值似乎没有意义。 这不是使用切片反转列表的正确方法,尝试schedule[-1::-1],或者更好的是reversed(schedule),因为切片无论如何都会构造一个新列表。 @FJ 类似for _ in range(sum('DELETE' in x for x in schedule)): schedule.remove(x) 的东西也同样有效——因为remove 无论如何都会进行搜索,所以您实际上只是使用匹配数而不是它们的位置,所以只需将这两个操作去同步,不需要反向操作,即使你想使用循环。 @agf:不,不幸的是——我的主要观点是驳斥你的说法,即[:] 是不必要的并且是浪费时间。循环版本已修复,谢谢。【参考方案3】:

您不应该在迭代列表时修改它:

for x in schedule:
    if 'DELETE' in x:
        schedule.remove(x)

请尝试:

schedule[:] = [x for x in schedule if 'DELETE' not in x]

欲了解更多信息,请参阅How to remove items from a list while iterating?

【讨论】:

没有必要从其他答案中复制就地分配,这并不好。 感谢您的回答和信息。老实说,我仍然不知道如何正确地询问有关 python 的问题或在哪里寻找答案。我不知道在迭代期间删除项目是不同的。 @Rodic:很高兴。这个问题是每个 Python 程序员迟早都会遇到的。 @agf: 如果不使用[:] 会产生错误,那么使用它会更好。详情见我的回答。【参考方案4】:

不要修改被迭代的序列。

schedule[:] = [x for x in schedule if 'DELETE' not in x]

【讨论】:

以上是关于迭代时从Python列表中删除项目[重复]的主要内容,如果未能解决你的问题,请参考以下文章

射击时从列表中删除外星人 - 找出循环; '表达式:不能增加结束列表迭代器'

如何在迭代字典时从字典中删除项目?

迭代时从 HashSet 中删除元素 [重复]

射击时从列表中删除外星人 - 找出循环; '表达式:无法增加结束列表迭代器'

Python - 从字典/列表中删除项目[重复]

Qt在迭代时从QMultiHash中删除项目