質問
Pythonでタプルのリストを繰り返し処理し、特定の条件に一致する場合は削除しようとしています。
for tup in somelist:
if determine(tup):
code_to_remove_tup
code_to_remove_tup
の代わりに何を使用すればよいですか?この方法でアイテムを削除する方法がわかりません。
解決
リスト内包表記を使用して、削除したくない要素のみを含む新しいリストを作成できます。
somelist = [x for x in somelist if not determine(x)]
または、スライス somelist [:]
に割り当てることで、既存のリストを変更して、必要なアイテムのみを含めることができます。
somelist[:] = [x for x in somelist if not determine(x)]
このアプローチは、変更を反映する必要がある somelist
への他の参照がある場合に役立ちます。
理解の代わりに、 itertools
を使用することもできます。 Python 2の場合:
from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)
またはPython 3の場合:
from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)
他のヒント
リストの内包を示唆する回答はほぼ正しいです-完全に新しいリストを作成し、古いリストと同じ名前を付けることを除いて、古いリストをその場で変更しません。 @Lennartの提案のように、選択的な削除で行うこととは異なります。 listは複数の参照を介してアクセスされます。参照の1つを再配置しているだけで、listオブジェクト自体を変更しないと、微妙で悲惨なバグにつながる可能性があります。
幸いなことに、リストの理解の速度と必要なインプレース変更のセマンティクスの両方を取得するのは非常に簡単です-コードだけ:
somelist[:] = [tup for tup in somelist if determine(tup)]
他の回答との微妙な違いに注意してください:これは裸の名前に割り当てられているのではなく、たまたまリスト全体になっているリストスライスに割り当てられているため、リストを置き換えます contents 他の回答のように1つの参照を(前のリストオブジェクトから新しいリストオブジェクトに)再配置するのではなく、同じPythonリストオブジェクト内で。
リストのコピーを取得して最初に反復処理する必要があります。そうしないと、反復が失敗して予期しない結果が生じる可能性があります。
例(リストの種類によって異なります):
for tup in somelist[:]:
etc....
例:
>>> somelist = range(10)
>>> for x in somelist:
... somelist.remove(x)
>>> somelist
[1, 3, 5, 7, 9]
>>> somelist = range(10)
>>> for x in somelist[:]:
... somelist.remove(x)
>>> somelist
[]
for i in range(len(somelist) - 1, -1, -1):
if some_condition(somelist, i):
del somelist[i]
後方に移動する必要があります。さもなければ、座っている木の枝をのこぎりで切るようなものです:-)
Python 2ユーザー: range
を xrange
に置き換えて、ハードコーディングされたリストを作成しないようにします
このような例に対する最善のアプローチは、リスト内包です
somelist = [tup for tup in somelist if determine(tup)]
determine
関数を呼び出すよりも複雑なことをしている場合、新しいリストを作成して、単純に追加することを好みます。例
newlist = []
for tup in somelist:
# lots of code here, possibly setting things up for calling determine
if determine(tup):
newlist.append(tup)
somelist = newlist
remove
を使用してリストをコピーすると、以下の回答の1つで説明するように、コードが少しきれいに見える場合があります。最初にリスト全体をコピーし、削除する各要素に対して O(n)
remove
操作を実行する必要があるため、非常に大きなリストに対しては絶対にこれを実行しないでください。これを O(n ^ 2)
アルゴリズムにします。
for tup in somelist[:]:
# lots of code here, possibly setting things up for calling determine
if determine(tup):
newlist.append(tup)
公式のPython 2チュートリアル4.2。 " for Statements"
https://docs.python.org/2/tutorial /controlflow.html#for-statements
ドキュメントのこの部分は、次のことを明確にします:
- 変更するには、反復リストのコピーを作成する必要があります
- その方法の1つは、スライス表記
[:]
を使用することです
ループ内で反復しているシーケンスを変更する必要がある場合(たとえば、選択したアイテムを複製するため)、最初にコピーを作成することをお勧めします。シーケンスを反復しても、暗黙的にコピーが作成されるわけではありません。スライス表記はこれを特に便利にします:
>>> words = ['cat', 'window', 'defenestrate'] >>> for w in words[:]: # Loop over a slice copy of the entire list. ... if len(w) > 6: ... words.insert(0, w) ... >>> words ['defenestrate', 'cat', 'window', 'defenestrate']
Python 2ドキュメント7.3。 " forステートメント"
https://docs.python.org/2/reference/compound_stmts .html#for
ドキュメントのこの部分では、コピーを作成する必要があることを再度説明し、実際の削除例を示します。
注:シーケンスがループによって変更されている場合、微妙な問題があります(これは、変更可能なシーケンス、つまりリストに対してのみ発生します)。内部カウンタは、次に使用されるアイテムを追跡するために使用され、これは各反復で増分されます。このカウンタがシーケンスの長さに達すると、ループが終了します。これは、スイートがシーケンスから現在の(または前の)アイテムを削除する場合、次のアイテムがスキップされることを意味します(すでに処理されている現在のアイテムのインデックスを取得するため)。同様に、スイートが現在のアイテムの前にシーケンス内のアイテムを挿入した場合、現在のアイテムは次回ループで再度処理されます。これは、シーケンス全体のスライスを使用して一時的なコピーを作成することで回避できる厄介なバグにつながる可能性があります。たとえば、
for x in a[:]: if x < 0: a.remove(x)
ただし、 .remove()
は値を見つけるためにリスト全体を反復処理する必要があるため、この実装には同意しません。
代わりに、次のいずれか:
-
新しい配列をゼロから開始し、最後に
.append()
を戻します: https://stackoverflow.com/a/1207460/895245この時間は効率的ですが、反復中に配列のコピーを保持するため、スペース効率が低下します。
-
インデックスで
del
を使用: https://stackoverflow.com/a/1207485 / 895245これは、配列のコピーをディスペンスするため、スペース効率が高くなりますが、CPythonは動的配列で実装されています。
これは、アイテムを削除するには、後続のすべてのアイテムを1つ戻す(O(N))必要があることを意味します。
一般に、メモリが大きな懸念事項でない限り、デフォルトではより高速な .append()
オプションを選択したいだけです。
Pythonでこれを改善できますか
この特定のPython APIは改善できるようです。たとえば、対応するJavaの ListIterator を使用すると、反復子自体を除いて反復されるリストを変更できないことが明確になり、リストをコピーせずに効率的に変更できます。
おそらく、基本的な理論的根拠は、Pythonリストは動的な配列に裏付けられていると想定されているため、いずれのタイプの削除もとにかく時間効率が悪くなりますが、Javaには <コード>
関数型プログラミングが好きな人向け:
somelist[:] = filter(lambda tup: not determine(tup), somelist)
または
from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))
現在のリストアイテムが目的の条件を満たしている場合、新しいリストを作成することも賢明です。
so:
for item in originalList:
if (item != badValue):
newList.append(item)
そして新しいリスト名でプロジェクト全体を再コーディングする必要を避けるために:
originalList[:] = newList
注、Pythonドキュメントから:
copy.copy(x) xの浅いコピーを返します。
copy.deepcopy(x) xのディープコピーを返します。
巨大なリストを使用してこれを行う必要があり、リストの複製は、特に私の場合、削除の数が残っているアイテムに比べて少ないため、費用がかかるようでした。この低レベルのアプローチを取りました。
array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
if someTest(array[i]):
del array[i]
arraySize -= 1
else:
i += 1
私が知らないのは、いくつかの削除が大きなリストをコピーすることと比較してどれだけ効率的かということです。洞察があればコメントしてください。
この回答は元々、重複としてマークされた質問への回答として書かれました。 Pythonのリストから座標を削除する
コードには2つの問題があります:
1)remove()を使用する場合、整数を削除しようとしますが、タプルを削除する必要があります。
2)forループはリスト内のアイテムをスキップします。
コードを実行するとどうなるかを見てみましょう:
>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
... if a < 0 or b < 0:
... L1.remove(a,b)
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)
最初の問題は、remove()に 'a'と 'b'の両方を渡していますが、remove()は単一の引数しか受け入れないことです。リストで適切に動作するようにremove()を取得するにはどうすればよいですか?リストの各要素を把握する必要があります。この場合、それぞれがタプルです。これを確認するには、リストの1つの要素にアクセスしましょう(インデックスは0から始まります):
>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>
あぁ! L1の各要素は実際にはタプルです。したがって、remove()に渡す必要があります。 Pythonのタプルは非常に簡単で、値を括弧で囲むだけで簡単に作成できます。 「a、b」タプルではありませんが、「(a、b)」タプルです。したがって、コードを変更して再度実行します。
# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))
このコードはエラーなしで実行されますが、出力されるリストを見てみましょう:
L1 is now: [(1, 2), (5, 6), (1, -2)]
なぜ(1、-2)がリストに残っているのですか?ループを使用してリストを反復処理しながらリストを変更することは、特別な注意を払わない非常に悪い考えです。 (1、-2)がリストに残っている理由は、forループの反復間でリスト内の各アイテムの位置が変わったためです。上記のコードに長いリストを入力するとどうなるか見てみましょう:
L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]
その結果から推測できるように、条件ステートメントがtrueに評価されてリスト項目が削除されるたびに、ループの次の繰り返しはリスト内の次の項目の評価をスキップします。異なるインデックス。
最も直感的な解決策は、リストをコピーしてから元のリストを反復処理し、コピーのみを変更することです。次のようにしてください:
L2 = L1
for (a,b) in L1:
if a < 0 or b < 0 :
L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)
ただし、出力は以前と同じになります。
'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]
これは、L2を作成したときに、Pythonが実際に新しいオブジェクトを作成しなかったためです。代わりに、L2をL1と同じオブジェクトに単に参照しました。これは単に「等しい」とは異なる「is」で確認できます。 (==)。
>>> L2=L1
>>> L1 is L2
True
copy.copy()を使用して真のコピーを作成できます。その後、すべてが期待どおりに動作します。
import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
if a < 0 or b < 0 :
L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]
最後に、完全に新しいL1のコピーを作成するよりも1つのクリーンなソリューションがあります。 reverse()関数:
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
if a < 0 or b < 0 :
L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]
残念ながら、reversed()の仕組みを適切に説明することはできません。リストが渡されると、「listreverseiterator」オブジェクトを返します。実際には、引数の逆のコピーを作成すると考えることができます。これが私が推奨する解決策です。
反復中に他に何かをしたい場合は、インデックス(たとえば、dictのリストがある場合に参照できることを保証します)と実際のリストアイテムの内容の両方を取得すると良いかもしれません。
inlist = [{'field1':10, 'field2':20}, {'field1':30, 'field2':15}]
for idx, i in enumerate(inlist):
do some stuff with i['field1']
if somecondition:
xlist.append(idx)
for i in reversed(xlist): del inlist[i]
enumerate
を使用すると、アイテムとインデックスに一度にアクセスできます。 reversed
は、後で削除するインデックスが変更されないようにするためです。
ビルトインとして利用可能な filter()
を使用したい場合があります。
詳細については、こちら
をご覧ください。for-loopingを逆に試すことができるので、some_listの場合は次のようにします:
list_len = len(some_list)
for i in range(list_len):
reverse_i = list_len - 1 - i
cur = some_list[reverse_i]
# some logic with cur element
if some_condition:
some_list.pop(reverse_i)
この方法でインデックスが整列され、リストの更新の影響を受けません(cur要素をポップするかどうかに関係なく)。
可能な解決策の1つは、いくつかのものを削除するだけでなく、すべての要素を1つのループで処理したい場合に便利です。
alist = ['good', 'bad', 'good', 'bad', 'good']
i = 0
for x in alist[:]:
if x == 'bad':
alist.pop(i)
i -= 1
# do something cool with x or just print x
print(x)
i += 1
ここでの回答のほとんどは、リストのコピーを作成することを望んでいます。リストが非常に長い(110Kアイテム)ユースケースがあり、代わりにリストを減らし続ける方が賢明でした。
まず、 foreachループをwhileループに置き換える、
i = 0
while i < len(somelist):
if determine(somelist[i]):
del somelist[i]
else:
i += 1
i
の値はifブロックで変更されません。古いアイテムが削除されると、新しいアイテムの値を同じインデックスから取得するためです。
似たようなことをする必要があり、私の場合は問題がメモリでした-リスト内の複数のデータセットオブジェクトを、新しいオブジェクトとして何らかの処理を行った後にマージし、各エントリを削除する必要がありましたそれらのすべてを複製してメモリを爆破するのを避けるためにマージしていました。私の場合、リストの代わりに辞書にオブジェクトがあるとうまくいきました:
`` `
k = range(5)
v = ['a','b','c','d','e']
d = {key:val for key,val in zip(k, v)}
print d
for i in range(5):
print d[i]
d.pop(i)
print d
`` `
TLDR:
これを可能にするライブラリを作成しました:
from fluidIter import FluidIterable
fSomeList = FluidIterable(someList)
for tup in fSomeList:
if determine(tup):
# remove 'tup' without "breaking" the iteration
fSomeList.remove(tup)
# tup has also been removed from 'someList'
# as well as 'fSomeList'
可能であれば、反復処理中にイテラブルを変更する必要のない別の方法を使用するのが最善ですが、一部のアルゴリズムでは簡単ではない場合があります。したがって、元の質問で説明されているコードパターンが本当に必要であると確信している場合は、可能です。
リストだけでなく、すべての可変シーケンスで動作するはずです。
完全な回答:
編集:この回答の最後のコード例は、 なぜ のユースケースを示しています。リスト内包表記を使用するのではなく、リストをその場で変更したい場合があります。回答の最初の部分は、配列をその場で変更できる のチュートリアルとして機能します。
解決策は、senderleからのこれの回答(関連する質問)に続きます。これは、変更されたリストを反復処理しながら配列インデックスが更新される方法を説明しています。以下のソリューションは、リストが変更された場合でも配列インデックスを正しく追跡するように設計されています。
fluidIter.py
をこちら https:/からダウンロードします/github.com/alanbacon/FluidIterator
、これは単一のファイルなので、gitをインストールする必要はありません。インストーラーがないため、ファイルが自分のpythonパスにあることを確認する必要があります。コードはpython 3用に作成されており、python 2ではテストされていません。
from fluidIter import FluidIterable
l = [0,1,2,3,4,5,6,7,8]
fluidL = FluidIterable(l)
for i in fluidL:
print('initial state of list on this iteration: ' + str(fluidL))
print('current iteration value: ' + str(i))
print('popped value: ' + str(fluidL.pop(2)))
print(' ')
print('Final List Value: ' + str(l))
これにより、次の出力が生成されます。
initial state of list on this iteration: [0, 1, 2, 3, 4, 5, 6, 7, 8]
current iteration value: 0
popped value: 2
initial state of list on this iteration: [0, 1, 3, 4, 5, 6, 7, 8]
current iteration value: 1
popped value: 3
initial state of list on this iteration: [0, 1, 4, 5, 6, 7, 8]
current iteration value: 4
popped value: 4
initial state of list on this iteration: [0, 1, 5, 6, 7, 8]
current iteration value: 5
popped value: 5
initial state of list on this iteration: [0, 1, 6, 7, 8]
current iteration value: 6
popped value: 6
initial state of list on this iteration: [0, 1, 7, 8]
current iteration value: 7
popped value: 7
initial state of list on this iteration: [0, 1, 8]
current iteration value: 8
popped value: 8
Final List Value: [0, 1]
上記では、流体リストオブジェクトで pop
メソッドを使用しました。 del fluidL [i]
、 .remove
、 .insert
、 .append
、 .extend
。リストはスライスを使用して変更することもできます( sort
および reverse
メソッドは実装されていません)。
唯一の条件は、任意の時点で fluidL
または l
がコードが機能しない別のリストオブジェクトに再割り当てされた場合にのみ、リストを修正する必要があることです。 。元の fluidL
オブジェクトはforループで引き続き使用されますが、修正の対象外になります。
i.e。
fluidL[2] = 'a' # is OK
fluidL = [0, 1, 'a', 3, 4, 5, 6, 7, 8] # is not OK
リストの現在のインデックス値にアクセスする場合、enumerateは使用できません。これは、forループが実行された回数のみをカウントするためです。代わりに、イテレータオブジェクトを直接使用します。
fluidArr = FluidIterable([0,1,2,3])
# get iterator first so can query the current index
fluidArrIter = fluidArr.__iter__()
for i, v in enumerate(fluidArrIter):
print('enum: ', i)
print('current val: ', v)
print('current ind: ', fluidArrIter.currentIndex)
print(fluidArr)
fluidArr.insert(0,'a')
print(' ')
print('Final List Value: ' + str(fluidArr))
これにより、次が出力されます。
enum: 0
current val: 0
current ind: 0
[0, 1, 2, 3]
enum: 1
current val: 1
current ind: 2
['a', 0, 1, 2, 3]
enum: 2
current val: 2
current ind: 4
['a', 'a', 0, 1, 2, 3]
enum: 3
current val: 3
current ind: 6
['a', 'a', 'a', 0, 1, 2, 3]
Final List Value: ['a', 'a', 'a', 'a', 0, 1, 2, 3]
FluidIterable
クラスは、元のリストオブジェクトのラッパーを提供するだけです。元のオブジェクトは、次のように流体オブジェクトのプロパティとしてアクセスできます。
originalList = fluidArr.fixedIterable
その他の例/テストは、 fluidIter.py
の下部にある if __name__が&quot; __ main __&quot;:
セクションにあります。これらはさまざまな状況で何が起こるかを説明するので、見る価値があります。など:スライスを使用してリストの大きなセクションを置き換える。または、ネストされたforループで同じiterableを使用(および変更)します。
最初に述べたように、これはコードの可読性を損ない、デバッグをより困難にする複雑なソリューションです。したがって、David Raznickの answer に記載されているリスト内包表記などの他のソリューションを最初に検討する必要があります。そうは言っても、このクラスが私にとって有用であり、削除が必要な要素のインデックスを追跡するよりも使いやすい時代を見つけました。
編集:コメントで述べたように、この答えはこのアプローチが解決策を提供する問題を実際に提示するものではありません。私はここでそれを解決しようとします:
リスト内包表記は新しいリストを生成する方法を提供しますが、これらのアプローチは各要素をtではなく分離して見る傾向があります
他の答えは正しいです。通常、反復しているリストから削除するのは悪い考えです。逆反復は落とし穴を回避しますが、それを行うコードを追跡することははるかに難しいため、通常はリスト内包表記または filter
を使用する方が良いでしょう。
ただし、反復しているシーケンスから要素を削除しても安全な場合が1つあります。反復中に1つのアイテムのみを削除する場合です。これは、 return
または break
を使用して確認できます。例:
for i, item in enumerate(lst):
if item % 4 == 0:
foo(item)
del lst[i]
break
これは、ある条件を満たすリストの最初の項目に副作用を伴う操作を行い、そのリストからすぐにその項目を削除する場合、リストを理解するよりも理解しやすいことがよくあります。
最も効果的な方法はリストの理解です。多くの人が自分の主張を示しています。もちろん、 filter
を通して iterator
を取得する良い方法でもあります。
Filter
は、関数とシーケンスを受け取ります。Filter
は、渡された関数を各要素に順番に適用し、関数の戻り値がTrue
かFalse <かどうかに応じて、要素を保持するか破棄するかを決定します/ code>。
例があります(タプルのオッズを取得):
list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))
# result: [1, 5, 9, 15]
注意:イテレータを処理することもできません。イテレータはシーケンスよりも優れている場合があります。
私はあなたの問題を解決する3つのアプローチを考えることができます。例として、タプルのランダムリストを作成します somelist = [(1,2,3)、(4,5,6)、(3,6,6)、(7,8,9)、 (15,0,0)、(10,11,12)]
。選択する条件は、タプルの要素の合計= 15
です。最終リストには、合計が15に等しくないタプルのみが含まれます。
私が選んだのは、ランダムに選ばれた例です。 自由に変更できます タプルのリストおよび選択した条件。
方法1.&gt; 提案したフレームワークを使用します(forループ内にコードを入力します)。 del
で小さなコードを使用して、上記の条件を満たすタプルを削除します。ただし、このメソッドは、連続して配置された2つのタプルが指定された条件を満たす場合、(上記の条件を満たす)タプルを見逃します。
for tup in somelist:
if ( sum(tup)==15 ):
del somelist[somelist.index(tup)]
print somelist
>>> [(1, 2, 3), (3, 6, 6), (7, 8, 9), (10, 11, 12)]
方法2.&gt; 指定された条件が満たされていない要素(タプル)を含む新しいリストを作成します(これは、指定された条件が満たされたリストの要素を削除するのと同じです) 。そのためのコードは次のとおりです。
newlist1 = [somelist[tup] for tup in range(len(somelist)) if(sum(somelist[tup])!=15)]
print newlist1
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]
方法3&gt; 指定された条件が満たされているインデックスを検索し、それらのインデックスに対応する要素(タプル)を削除します。以下はそのためのコードです。
indices = [i for i in range(len(somelist)) if(sum(somelist[i])==15)]
newlist2 = [tup for j, tup in enumerate(somelist) if j not in indices]
print newlist2
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]
方法1と方法2は方法3よりも高速です。 method2とmethod3はmethod1よりも効率的です。 method2を優先します。前述の例では、 time(method1):time(method2):time(method3)= 1:1:1.7
forループはインデックスを反復処理します。
リストがあることを考慮してください
[5, 7, 13, 29, 65, 91]
lis
というリスト変数を使用しています。削除するには同じものを使用します。
変数
lis = [5, 7, 13, 29, 35, 65, 91]
0 1 2 3 4 5 6
5回目の反復中、
番号35 は素数ではなかったため、リストから削除しました。
lis.remove(y)
次に次の値(65)で前のインデックスに移動します。
lis = [5, 7, 13, 29, 65, 91]
0 1 2 3 4 5
そのため、4番目の反復が完了し、ポインターが5番目に移動しました。
ループが前のインデックスに移動してから65をカバーしない理由です。
したがって、コピーではなく元の変数を参照している別の変数にリストを参照しないでください。
ite = lis #dont do it will reference instead copy
list [::]
今、あなたはそれを与えるでしょう、
[5, 7, 13, 29]
問題は、反復中にリストから値を削除すると、リストインデックスが崩壊することです。
だから、代わりに理解を試みることができます。
すべての反復可能なlike、list、tuple、dict、stringなどをサポートします
本当に大きくなる可能性があるものについては、以下を使用します。
import numpy as np
orig_list = np.array([1, 2, 3, 4, 5, 100, 8, 13])
remove_me = [100, 1]
cleaned = np.delete(orig_list, remove_me)
print(cleaned)
これは、他の何よりもはるかに高速でなければなりません。
リストを一度に1項目だけフィルタリングする以上のことを行う状況では、反復中に反復を変更したい場合があります。
事前にリストをコピーするのは正しくなく、逆反復は不可能であり、リストの理解もオプションではない例です。
""" Sieve of Eratosthenes """
def generate_primes(n):
""" Generates all primes less than n. """
primes = list(range(2,n))
idx = 0
while idx < len(primes):
p = primes[idx]
for multiple in range(p+p, n, p):
try:
primes.remove(multiple)
except ValueError:
pass #EAFP
idx += 1
yield p
後で新しいリストを使用する場合は、elemをNoneに設定し、次のように後のループで判断することができます
for i in li:
i = None
for elem in li:
if elem is None:
continue
この方法では、リストをコピーする必要がなく、理解しやすくなります。
数字のリストを想定し、3で割り切れるすべてのnoを削除したい
list_number =[i for i in range(100)]
list comprehension
を使用すると、新しいリストが保持され、新しいメモリスペースが作成されます
new_list =[i for i in list_number if i%3!=0]
lambda filter
関数を使用して、結果の新しいリストを作成し、記憶領域を消費します
new_list = list(filter(lambda x:x%3!=0, list_number))
新しいリストのメモリスペースを消費せずに、既存のリストを変更します
for index, value in enumerate(list_number):
if list_number[index]%3==0:
list_number.remove(value)
リストのコピーを作成して、リスト内の特定の条件を満たすタプルを繰り返し削除するときに参照として使用できるようにします。
それは、削除されたタプルのリストであるか、削除されていないタプルのリストであるか、出力に必要なリストのタイプによって異なります。
Davidが指摘したように、削除したくない要素を保持するためにリストの理解をお勧めします。
somelist = [x for x in somelist if not determine(x)]