迭代时从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
返回分配回schedule
的sched
,或者在被认为是错误的形式但合乎逻辑的设计中,您没有通过时间表你使用global schedule
。无论您是否使用就地分配,上面的示例设计都是错误的,因为不清楚sched
和schedule
在您更改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列表中删除项目[重复]的主要内容,如果未能解决你的问题,请参考以下文章
射击时从列表中删除外星人 - 找出循环; '表达式:不能增加结束列表迭代器'