簡體   English   中英

在迭代過程中刪除python列表的元素

[英]Deleting elements of a python list during iteration

我有我必須完成許多操作每個元素非常大名單。 本質上,列表的每個元素都以各種方式附加到其上,然后用於生成對象。 這些對象然后用於生成另一個列表。

不幸的是,以幼稚的方式執行此操作會占用所有可用內存。

因此,我想做以下事情:

for a in b:
    # Do many things with a
    c.append(C(modified_a))
    b[b.index(a)] = None # < Herein lies the rub

這似乎違反了在迭代過程中不應修改列表的想法。 有沒有更好的方法來進行這種手動垃圾收集?

這應該不成問題,因為您只是將新值分配給列表元素,而不是真正刪除它們。

但是,可能不應該使用枚舉來搜索索引方法,而不必使用index方法。

另請參見此處: http : //unspecified.wordpress.com/2009/02/12/thou-shalt-not-modify-a-list-during-iteration/ “首先,請允許我在本文中明確指出說“修改”,我的意思是從列表中插入或刪除項目。僅更新或變異列表項目就可以了。”

最好的選擇是生成器

def gen(b):
   for a in b:
      # Do many things with a
      yield a

此處正確完成,不需要額外的內存。

您的代碼有幾個問題。

首先,為列表元素分配None不會將其刪除:

>>> l=[1,2,3,4,5,6,6,7,8,9]
>>> len(l)
10
>>> l[l.index(5)]=None
>>> l
[1, 2, 3, 4, None, 6, 6, 7, 8, 9]
>>> len(l)
10

其次,使用索引查找要更改的元素根本不是有效的方法。

您可以使用枚舉,但是您仍然需要遍歷以刪除None值。

for i,a in enumerate(b):
    # Do many things with a
    b[i]=C(modified_a)
    b[i]=None 
c=[e for e in b if e is not None]

您可以使用列表推導將新的“ a”值復制到c列表中,然后刪除b:

c=[do_many_things(a) for a in b]
del b                              # will still occupy memory if not deleted...

或者,如果您想在適當位置修改b,則可以使用slice分配

b[:]=[do_many_things(a) for a in b]

切片分配以這種方式工作:

#shorted a list
>>> b=[1,2,3,4,5,6,7,8,9]
>>> b[2:7]=[None]
>>> b
[1, 2, None, 8, 9]

#expand a list
>>> c=[1,2,3]
>>> c[1:1]=[22,33,44]
>>> c
[1, 22, 33, 44, 2, 3]

# modify in place
>>> c=[1,2,3,4,5,6,7]
>>> c[0:7]=[11,12,13,14,15,16,17]
>>> c
[11, 12, 13, 14, 15, 16, 17]

您可以像這樣在列表理解中使用它:

>>> c=list(range(int(1e6)))
>>> c[:]=[e for e in c if e<10]
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

其中一項評論指出,切片分配未完全修改到位。 生成臨時列表。 那是真實的。 但是,讓我們在這里查看總時間:

import time
import random
fmt='\t{:25}{:.5f} seconds' 
count=int(1e5)
a=[random.random() for i in range(count)]
b=[e for e in a]

t1=time.time()
for e in b:
    if e<0.5: b[b.index(e)]=None  
c=[e for e in b if e is not None]    
print(fmt.format('index, None',time.time()-t1))

b=[e for e in a]
t1=time.time()
for e in b[:]:
    if e<0.5: del b[b.index(e)]  
print(fmt.format('index, del',time.time()-t1))

b=[e for e in a]
t1=time.time()
for i,e in enumerate(b[:]):
    if e<0.5: b[i]=None
c=[e for e in b if e is not None]    
print(fmt.format('enumerate, copy',time.time()-t1))

t1=time.time()
c=[e for e in a if e<.5]
del a
print(fmt.format('c=',time.time()-t1))

b=[e for e in a]
t1=time.time()
b[:]=[e for e in b if e<0.5]
print(fmt.format('a[:]=',time.time()-t1))

在我的計算機上,打印以下內容:

index, None              87.30604 seconds
index, del               28.02836 seconds
enumerate, copy          0.02923 seconds
c=                       0.00862 seconds
a[:]=                    0.00824 seconds

或者,如果這樣做沒有幫助,請使用numpy以獲得更優化的數組選項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM