2013-11-26 64 views
0

我有我使用的地理列表測試成員,並從這次失敗檢查預算清單中刪除條目的方法的問題。有趣的是,這種方法需要運行3次抓到失敗的條目100%之前。Python測試會員限制?

BUDG元素例子:

budg = ['KELOG_PSOD_32773         20131125 000327 73144652.3376898.6 9769.50', 'KELOG_PSOD_32774         20131125 000327 74140034.3406629.9 4473.90'] 

地理元素的例子:

geolist = ['KELOG_GEO_32773','KELOG_GEO_32775'] 

def remove_entry(budg, geolist): 
    for e in budg: 
     record = 'KELOG_GEO_' + e[11:e.index(' ')] 
     if record not in geolist: 
      print e 
      removed.append(budg.pop(budg.index(e))) 

我針對每個約爲2500項列表運行此。截至今天,44個失敗的條目存在於預算列表中。一直運行此方法後,始終在預算列表中總有7個誤報。然後他們中的4人被第二次抓住。最後剩下的3個在第三輪中找到。我知道我可以只運行的方法3次在我的劇本和收工,但是這真的開始來煩我。

我試着對列表進行反向排序,並且足夠有趣我在第一次嘗試中抽取了44個失敗項目中的37個,但其中一些是第二個和第三個項目,如果我不反向排序列表。

是否有任何你知道的成員資格測試的任何限制,我可以用這個代碼違反?有沒有人看到過像這樣的列表行爲?

回答

7

您正在從budg中刪除元素,同時在其上循環播放

>>> lst = [1, 2, 3] 
>>> for i in lst: 
...  print i 
...  lst.remove(i) 
... 
1 
3 

這裏2被跳過,因爲迭代器首先處理lst[0],然後轉移到lst[1]它通過當時是從列表與[2, 3]在裏面,沒有:當你這樣做的for循環迭代不更新其索引[1, 2, 3]

使用while循環,而不是:

i = 0 
while i < len(budg): 
    e = budg[i] 
    record = 'KELOG_GEO_' + e.split(None, 1)[0][11:] 
    if record not in geolist: 
     removed.append(budg.pop(i)) 
    else: 
     i += 1 

現在您可以直接控制哪些指標你正在處理,只有增加i移除元素。

+0

你也可以在xrange(len(budg)-1,-1,-1)中使用'for i:'向後跨越列表,那麼你不必有一個特殊的處理程序來有條件地修改計數器。 –

+1

@SilasRay:當然,但是你必須反過來去掉'',或者在開始時插入。 –

+0

夠正確。猜測歸結到「去除」與「budg」相比,哪個最好。 –

1

在迭代它時,不應從列表中刪除元素。其原因是,它可修改元素的索引刪除並,反過來,改變其中的循環將繼續迭代。

你應該找出哪些元素先刪除,然後刪除它們。

+1

或者向後退出列表而不是轉發;那麼你可以通過一次而不是2次來完成。 –

0

的問題是你改變你遍歷列表。有多種方法可以避免這種情況。一個容易理解和快速的方法是創建一個新列表,並省去你想要刪除的項目,然後用原來的列表替換原來的列表。這就是我的意思是:

budg = ['KELOG_PSOD_32773         20131125 000327 73144652.3376898.6 9769.50', 
     'KELOG_PSOD_32774         20131125 000327 74140034.3406629.9 4473.90'] 

geoset = {'KELOG_GEO_32773', 'KELOG_GEO_32775'} # note this is now a set 

def remove_entry(budg, geoset): 
    cleaned = [] 
    for e in budg: 
     record = 'KELOG_GEO_' + e[11:e.index(' ')] 
     if record in geoset: # keep it 
      cleaned.append(e) 
    budg[:] = cleaned 

remove_entry(budg, geolist) 
print 'budg:', budg 

關於這種方法的另一個好處是,它可以減少到一行代碼:

budg = [e for e in budg if 'KELOG_GEO_' + e[11:e.index(' ')] in geoset] 

如在修改後的代碼開頭附近的評論指出,我將geolist更改爲geoset,因爲如果列表較大,則測試set中的成員資格通常比檢查列表中的成員要快得多。