奇怪的行为从Python中的循环中的列表中删除元素

问题描述:

我知道,如果您当前正在遍历该列表,则无法从列表中删除元素。我想要做的是从列表中复制我不希望移除到另一个列表中的元素,然后用新列表替换原始列表。这里是我的相关代码:奇怪的行为从Python中的循环中的列表中删除元素

while len(tokenList) > 0: 
    # loop through the tokenList list 

    # reset the updated token list and the remove flag 
    updatedTokenList = [] 
    removeFlag = False 

    for token in tokenList: 

     completionHash = aciServer.checkTaskForCompletion(token) 

     # If the completion hash is not the empty hash, parse the information 
     if completionHash != {}: 
      # if we find that a task has completed, remove it from the list 
      if completionHash['Status'] == 'FINISHED' and completionHash['Error'] == '': 
       # The task completed successfully, remove the token from the list 
       removeFlag = True 

      elif completionHash['Status'] == 'RUNNING' and completionHash['Error'] == '': 
       # The task must still be running 
       print('Task ' + completionHash['Type'] + ' ' + token + ' has been running for ' + completionHash['Runtime'] + ' seconds.') 

      elif completionHash['Status'] == 'queued': 
       # The task is in the queue 
       print('Task ' + completionHash['Type'] + ' ' + token + ' is queued in position ' + completionHash['QueuePosition']) 

      elif completionHash['Status'] == 'not_found': 
       # Did not find a task with this token, possible the task hasn't been added yet 
       print(completionHash['Error']) 

      # if the task is still running, no change to the token list will have occured 

     else: 
      # This is probably because the server got rid of the token after the task completed 
      print('Completion hash is empty, something went wrong.') 

      tokenListError.append(token) 
      removeFlag = True 

     if not removeFlag: 
      print('appending token to updatedTokenList') 
      updatedTokenList.append(token) 


    print('length of tokenList after removal loop: ' + str(len(updatedTokenList))) 

    # wait some time, proportional to the number of tasks left 
    checkInterval = len(updatedTokenList) * checkIntervalMultiplier 

    print('Waiting ' + str(checkInterval) + ' seconds before checking again...') 
    print('Tokens remaining: ' + str(len(updatedTokenList))) 

    # replace the original token list with the updated token list 
    tokenList = updatedTokenList 

    # wait a while based on how many tokens remain 
    time.sleep(checkInterval) 

因此,所有这一切的重点是更新tokenList与新列表。每次循环时,新任务都已完成,不应将其添加到updatedTokenList。剩下的任务令牌将会替换原始的令牌列表。

这不起作用。在我第一次通过时,即使尚未完成任务,它也不会将任何标记添加到updatedTokenList。我无法弄清楚我做错了什么。有什么建议么?

+0

对于初学者,您应该在循环的每次迭代开始时将'removeFlag'重置为'False'。这可能是第一项任务已完成,并且由于'removeFlag'永远不会重置为'False',所以您将删除所有任务。如果这不能解决您的问题,请尝试单步执行代码并查看checkTaskForCompletion()返回的内容,验证您是否拥有正确的if条件。 – acattle 2013-05-03 01:29:51

情况就会变得容易得多,如果你移动逻辑到一个函数:

#This function should have a more descriptive name that follows your 
#project's API. 
def should_keep(token): 
    """returns True if the token should be kept""" 
    #do other stuff here. Possibly print stuff or whatever ... 
    ... 

现在,你可以用一个简单的列表理解取代你的列表:

tokenList = [ token for token in tokenList if should_keep(token) ] 

需要注意的是我们的避风港” t 实际上取代了列表。旧名单仍然可能有其参考。如果你想尽可能地替换列表,这没有问题。我们只是用切片赋值:

tokenList[:] = [ token for token in tokenList if should_keep(token) ] 
+0

想要一石二鸟。如果可能,最好做两个循环,一个用于过滤。 – n611x007 2013-10-31 11:43:44

+0

是的,通常在编程中我会说每块石头上的一只鸟会导致更容易阅读代码。 – mgilson 2013-10-31 17:10:13

一个问题是,在第一次遇到应该删除的令牌后,您从未将removeFlag设置为False。只要它检测到一个应该被删除,它也会从列表中删除所有的令牌。您需要在所有completionHash elifs中将其设置为False(并确保它们测试的状态值是唯一的可能性),或者将它立即设置在您的for token in tokenlist循环中。

如果在测试中第一个作业你的时间完成第一次检查完成后,将符合描述的行为。

我明白你想删除列表中的项目,而不让他们,所以,我觉得你可以做的是保存对应于您要删除列表中的项目数量。例如,假设我有一个包含1到5的数字的列表,但我只希望这个列表得到奇数,所以我想删除偶数。我要做的是设置一个循环与计数器,检查列表中的每个项目的条件(在这种情况下,我会检查是否myList[ItemNumber] % 2 == 0),如果它确实,我会将ItemNumber设置为另一个列表中的项目。然后,当所有要删除的项目在这个新列表中都有他们的号码时,我会调用另一个循环来遍历这个新列表,并从另一个列表中删除那些包含在新列表中的项目。像这样:

myList = [1, 2, 3, 4, 5] 
count = 0 
toBeDeleted = [] 
while count < len(myList): 
    if myList[count] % 2 == 0: 
     toBeDeleted.append(count) 
    count += 1 

cont2 = len(toBeDeleted) 
while cont2 > 0: 
    cont3 = toBeDeleted[cont2 - 1] 
    myList.pop(cont3) 
    cont2 -= 1 

这对这个问题很好,所以我相信并希望它能帮助你。