【问题标题】:Delete item from list in Python while iterating over it [duplicate]迭代时从Python列表中删除项目[重复]
【发布时间】: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

【问题讨论】:

    标签: python list


    【解决方案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]
    

    【讨论】:

      猜你喜欢
      • 2017-09-17
      • 1970-01-01
      • 2014-10-26
      • 2020-05-27
      • 1970-01-01
      • 2011-09-29
      • 2013-08-03
      • 1970-01-01
      相关资源
      最近更新 更多