0

私は多くの操作をしなければならない各要素について非常に大きなリストを持っています。基本的に、リストの各要素はさまざまな方法で追加され、オブジェクトを生成するために使用されます。これらのオブジェクトは、別のリストを生成するために使用されます。

残念ながら、これを単純な方法で行うと、使用可能なすべてのメモリが消費されます。

したがって、私は次のことをしたいと思います。

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

これは、反復中にリストを変更してはならないという考えに違反しているようです。この種の手動ガベージコレクションを行うためのより良い方法はありますか?

4

3 に答える 3

2

リスト要素に新しい値を割り当てるだけで、実際には削除しないので、これは問題にはなりません。

ただし、indexメソッドでを検索する代わりに、おそらくenumerateを使用する必要があります。

こちらもご覧ください:http: //unspecific.wordpress.com/2009/02/12/thou-shalt-not-modify-a-list-during-iteration/ "まず、この記事で、私が「変更」とは、リストにアイテムを挿入または削除することを意味します。リストアイテムを更新または変更するだけで問題ありません。」

于 2013-02-13T20:03:02.980 に答える
0

あなたの最善の策はジェネレーターです:

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

ここで適切に実行され、追加のメモリは必要ありません。

于 2013-02-14T06:27:07.927 に答える
-1

コードにはいくつかの問題があります。

まず、リスト要素に割り当て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

次に、インデックスを使用して変更する要素を見つけることは、これを行うための効率的な方法ではありません。

enumerateを使用できますが、値を削除するにはループスルーする必要があり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をその場で変更したい場合は、スライス割り当てを使用できます。

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]

コメントの1つは、スライスの割り当てがその場で正確に変更されないことを指摘しました。一時リストが生成されます。それは本当です。ただし、ここで合計タイミングを見てみましょう。

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を使用します。

于 2013-02-13T20:11:28.473 に答える