2013-05-03 89 views
2

我知道,如果您當前正在遍歷該列表,則無法從列表中刪除元素。我想要做的是從列表中複製我不希望移除到另一個列表中的元素,然後用新列表替換原始列表。這裏是我的相關代碼:奇怪的行爲從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

回答

5

情況就會變得容易得多,如果你移動邏輯到一個函數:

#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

0

一個問題是,在第一次遇到應該刪除的令牌後,您從未將removeFlag設置爲False。只要它檢測到一個應該被刪除,它也會從列表中刪除所有的令牌。您需要在所有completionHash elifs中將其設置爲False(並確保它們測試的狀態值是唯一的可能性),或者將它立即設置在您的for token in tokenlist循環中。

如果在測試中第一個作業你的時間完成第一次檢查完成後,將符合描述的行爲。

0

我明白你想刪除列表中的項目,而不讓他們,所以,我覺得你可以做的是保存對應於您要刪除列表中的項目數量。例如,假設我有一個包含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 

這對這個問題很好,所以我相信並希望它能幫助你。