2015-10-18 56 views
1

嘿,我正在從stackoverflow上的另一篇文章中研究代碼,我注意到了一些關於「for循環」的內容。如果使用「pop」或「remove」來更改列表,則會混淆該內部循環的索引。如果您從列表中彈出/刪除項目,它將跳過整個項目。我解決這個問題的方法是,在我操縱另一個列表時,實際製作一份列表的副本以用於「for循環」。我新來python。用於循環和操作的Python

我已添加到他的列表中。我的程序刪除了超過180的任何人或任何名爲joe的人。起初,我只是在注意到這個問題時才使用d_list。然後,我只是「temp_list = d_list」,我認爲這是一個單獨的副本,但我猜並沒有。然後我使用列表的複製屬性使其工作。這樣我就不會操縱「for循環」使用的列表。

我的問題是,這是正常的,我有沒有解決它的權利?對於我來說,如果數據很大,你不會想複製數據。我想出的另一種方法是使用while循環而不是外循環。

d_list = [ {'id':1, 'Name': 'Hannah', 'weight':150}, {'id':2, 'Name':'Andrew', 'weight':200}, {'id':3, 'Name':'Joe', 'weight':180}, 
      {'id':4, 'Name':'Joe', 'weight':180}, {'id':5, 'Name':'Steve', 'weight':200}, {'id':6, 'Name':'Joe', 'weight':180}, 
      {'id':7, 'Name':'George', 'weight':180}] 

temp_list = d_list 
#temp_list = d_list.copy() 
print(d_list) 
i = 0 
for item in temp_list: # may make a while loop 
    print(item, "i = ", i, end="[") 
    for k, v in item.items(): 
     print(end="*") 
     if (k == "weight") and (v > 180): 
      d_list.pop(i) 
      print('^popped^', i, end="") # <-- pop but you need an index 
      i -= 1 
     elif (k == "Name") and (v == "Joe"): 
      d_list.remove(item)   # <-- remove just uses item to find and remove 
      print("^removed^", i, end="") 
      i -= 1 
    i += 1 
    print("]") 
print(d_list) 
print("i = ", i) 
+1

這不是平常的,因爲'彈出列表和刪除列表通常不用於有效的解決方案。通常對於簡單的事情,你會使用列表理解。對於更復雜的事情,像@alexis回答中的for循環。這對初學者來說是不直觀的,但是製作一個全新的列表通常比以這種方式修改一個列表更有效。 –

回答

0

temp_list = d_list創建參考所以在任一列表中的任何更改都將反映在,這樣就肯定是不行的。 temp_list = d_list.copy()創建一個淺表副本將工作和會temp_list = d_list[:]但更好的方法,以避免任何複製都將是使用reversed,只是從列表中刪除的元素:

for item in reversed(d_list): 
    if item.get("weight", 0) > 180 or item.get("Name") == "Joe": 
     d_list.remove(item) 
     i -= 1 

如果你想彈出你可以開始在使用範圍內以相反的端部:

for i in range(len(d_list) -1 , -1, - 1): 
    item = d_list[i] 
    if item.get("weight", 0) > 180 or item.get("Name") == "Joe": 
     i -= 1 

第三種選擇是使用list comprehensiond_list[:]突變原始對象/列表:

d_list[:] = [d for d in d_list if d.get("weight", 0) <= 180 and d.get("Name") != "Joe"] 

或者用generator expression結合起來:

d_list[:] = (d for d in d_list if d.get("weight", 0) <= 180 and d.get("Name") != "Joe") 

所有這些方法都將給你相同的輸出。使用dict.get而不是迭代所有項目也是更有效的解決方案,我們每次迭代執行兩次查找,而不是查看每個字典中的所有鍵和值。

使用python3一些計時:

In [14]: %%timeit 
d_list = [{'id': 1, 'Name': 'Hannah', 'weight': 150}, {'id': 2, 'Name': 'Andrew', 'weight': 200}, 
      {'id': 3, 'Name': 'Joe', 'weight': 180}, 
      {'id': 4, 'Name': 'Joe', 'weight': 180}, {'id': 5, 'Name': 'Steve', 'weight': 200}, 
      {'id': 6, 'Name': 'Joe', 'weight': 180}, 
      {'id': 7, 'Name': 'George', 'weight': 180}] 
for item in reversed(d_list):  
    if item.get("weight", 0) > 180 or item.get("Name") == "Joe": 
     d_list.remove(item) 
    ....: 
100000 loops, best of 3: 4.35 µs per loop 

In [15]: %%timeit 
d_list = [{'id': 1, 'Name': 'Hannah', 'weight': 150}, {'id': 2, 'Name': 'Andrew', 'weight': 200}, 
      {'id': 3, 'Name': 'Joe', 'weight': 180}, 
      {'id': 4, 'Name': 'Joe', 'weight': 180}, {'id': 5, 'Name': 'Steve', 'weight': 200}, 
      {'id': 6, 'Name': 'Joe', 'weight': 180}, 
      {'id': 7, 'Name': 'George', 'weight': 180}] 
for i in range(len(d_list) - 1, -1, - 1): # may make a while loop 
    item = d_list[i] 
    if item.get("weight", 0) > 180 or item.get("Name") == "Joe": 
     d_list.pop(i) 
    ....: 
    ....:  
100000 loops, best of 3: 4.48 µs per loop 

In [16]: %%timeit 
    ....: d_list = [{'id': 1, 'Name': 'Hannah', 'weight': 150}, {'id': 2, 'Name': 'Andrew', 'weight': 200}, 
    ....:   {'id': 3, 'Name': 'Joe', 'weight': 180}, 
    ....:   {'id': 4, 'Name': 'Joe', 'weight': 180}, {'id': 5, 'Name': 'Steve', 'weight': 200}, 
    ....:   {'id': 6, 'Name': 'Joe', 'weight': 180}, 
    ....:   {'id': 7, 'Name': 'George', 'weight': 180}] 
    ....: d_list[:] = (d for d in d_list if d.get("weight", 0) <= 180 and d.get("Name") != "Joe") 
    ....: 
100000 loops, best of 3: 3.23 µs per loop 

In [17]: %%timeit 
d_list = [{'id': 1, 'Name': 'Hannah', 'weight': 150}, {'id': 2, 'Name': 'Andrew', 'weight': 200}, 
      {'id': 3, 'Name': 'Joe', 'weight': 180}, 
      {'id': 4, 'Name': 'Joe', 'weight': 180}, {'id': 5, 'Name': 'Steve', 'weight': 200}, 
      {'id': 6, 'Name': 'Joe', 'weight': 180}, 
      {'id': 7, 'Name': 'George', 'weight': 180}] 
d_list[:] = [d for d in d_list if d.get("weight", 0) <= 180 and d.get("Name") != "Joe"] 
    ....: 
100000 loops, best of 3: 2.98 µs per loop 

所以列表比較是最快其次是根EXP。如果你知道密鑰總是存在,那麼訪問d["weight"] etc ..也會再次更快

+0

謝謝。有效。 – James

+0

如何使用while循環而不是爲了循環而顛倒?無論哪種方式都有優勢 – James

+0

@詹姆斯,使用反向使用沒有額外的空間 –

1

由於你確定的問題,這種事情最好通過創建一個新的限定元素列表來完成。另外,掃描所有的鍵和值都很愚蠢,字典是爲了通過查找鍵可用於:

newlist = [] 
for item in d_list: 
    if item["weight"] <= 180 and item["Name"] != "Joe": 
     newlist.append(item) 

然後,您可以騰出舊列表,如果你擔心「浪費」空間:

del d_list