私は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の提案のように、選択的な削除で行っていることとは異なります。複数の参照を介してリストにアクセスする場合は、参照の1つを再挿入してリストオブジェクトを変更しないという事実です。それ自体が微妙な、悲惨なバグにつながる可能性があります。
幸い、リスト内包表記の速度とインプレース変更に必要なセマンティクスの両方を得るのは非常に簡単です。
somelist[:] = [tup for tup in somelist if determine(tup)]
他の答えとの微妙な違いに注意してください:これは素の名前に割り当てているのではありません - それはたまたまリスト全体になるリストスライスに割り当てているので、同じPythonリスト内のlist contents を置き換えます。 object 他の答えのように(前のリストオブジェクトから新しいリストオブジェクトへの)1つの参照を再配置するのではなく。
あなたは最初にリストのコピーを取ってそれを反復する必要があります、さもなければ反復は予想外の結果になるかもしれないもので失敗するでしょう。
たとえば(リストの種類によって異なります)。
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。 "ステートメント用"
https://docs.python.org/2/tutorial/controlflow.html#for-statements
ドキュメントのこの部分は、次のことを明確にしています。
[:]
を使うことですループ内で反復している順序を変更する必要がある場合(たとえば選択した項目を複製する場合など)は、最初にコピーを作成することをお勧めします。シーケンスを反復しても、暗黙のうちにコピーは作成されません。スライス表記はこれを特に便利にします。
>>> 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は ArrayList
と LinkedList
の実装を持つより良いインターフェース階層を持ちますListIterator
。
Pythonのstdlibには明示的なリンクリスト型も存在しないようです: Python Linked List
関数型プログラミングが好きな人のために:
somelist[:] = filter(lambda tup: not determine(tup), somelist)
または
from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))
現在のリスト項目が目的の基準を満たしている場合は、新しいリストを作成するだけでも賢明です。
そう:
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()を使用するとき、整数を削除しようとしますが、Tupleを削除する必要があります。
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)
1つ目の問題は、 'a'と 'b'の両方をremove()に渡すことですが、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)]
その結果から推測できるように、条件ステートメントが真と評価されてリスト項目が削除されるたびに、ループの次の反復ではリスト内の次の項目の評価がスキップされます。
最も直感的な解決策は、リストをコピーしてから元のリストを反復処理してそのコピーを修正することです。あなたはこのようにやってみることができます:
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)]
残念ながら、reverse()がどのように機能するかについては十分に説明できません。リストが渡されると 'listreverseiterator'オブジェクトを返します。実用的には、その議論の逆のコピーを作成すると考えることができます。これが私がお勧めする解決策です。
ビルトインとして利用可能なfilter()
を使いたいかもしれません。
詳細については こちらをチェック
繰り返しの間に他に何かしたいのであれば、インデックス(あなたがそれを参照することができることを保証する、例えばあなたがdictsのリストを持っているならば)と実際のリストアイテムコンテンツの両方を得るのはいいかもしれません。
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
は、後で削除しようとしているインデックスが変更されないようにするためです。
逆に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つは、いくつかのものを削除するだけでなく、すべての要素を単一のループで処理する場合に便利です。
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
私は似たようなことをする必要があり、私の場合は問題はメモリでした。新しいオブジェクトとしてそれらを使っていくつかのデータセットオブジェクトをマージし、マージした各エントリを取り除く必要がありましたそれらすべてを複製してメモリを消費することは避けてください。私の場合は、リストではなく辞書にオブジェクトを入れても問題ありませんでした。
`` `
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'
可能であれば、反復処理中に反復可能オブジェクトを変更する必要がない別の方法を使用するのが最善ですが、アルゴリズムによってはそれほど単純ではない場合があります。したがって、元の質問で説明されているコードパターンが本当に必要であると確信できる場合は、可能です。
リストだけではなく、すべてのミュータブルシーケンスで動作するはずです。
完全な答え:
編集:この答えの最後のコード例はwhy _ のためのユースケースを示していますあなたは時々リスト内包表記を使うよりむしろその場でリストを修正したいかもしれません。答えの最初の部分はhowのチュートリアルとして使われ、配列はその場で修正できます。
解決策は、senderleからの this answer(関連する質問に対する)に続きます。これは、変更されたリストを反復処理しながら配列インデックスが更新される方法を説明しています。以下の解決策は、リストが変更された場合でも配列インデックスを正しく追跡するように設計されています。
herefluidIter.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ループによって使用されますが、変更することができなくなります。
すなわち.
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
if __is "__main__":
の下部にあるfluidIter.py
セクションに、より多くの例/テストがあります。これらは、さまざまな状況で何が起こるのかを説明しているので、検討する価値があります。スライスのようにリストの大きな部分を置き換える。または、同じイテラブルをネストされたforループで使用(および変更)します。
最初に述べたように、これはあなたのコードの可読性を損ない、デバッグをより困難にする複雑な解決策です。したがって、David Raznickの answer に記載されているリスト内包表記などの他の解決策を最初に検討する必要があります。そうは言っても、削除が必要な要素のインデックスを追跡するよりも、このクラスが便利で使いやすい場合があります。
編集:コメントで述べたように、この答えは実際にはこのアプローチが解決策を提供する問題を提示していません。私はここでそれに対処しようとします:
リスト内包表記は新しいリストを生成する方法を提供しますが、これらのアプローチはリスト全体の現在の状態ではなく各要素を個別に見る傾向があります。
すなわち.
newList = [i for i in oldList if testFunc(i)]
しかし、testFunc
の結果がすでにnewList
に追加されている要素に依存しているとしたらどうでしょうか。それともoldList
の中にまだ追加されているかもしれない要素がありますか?リスト内包表記を使用する方法はまだあるかもしれませんが、それはその優雅さを失い始めます、そして私にとってそれはその場でリストを修正することがより簡単であると感じます。
以下のコードは、上記の問題を抱えているアルゴリズムの一例です。どの要素も他の要素の倍数にならないように、アルゴリズムはリストを減らします。
randInts = [70, 20, 61, 80, 54, 18, 7, 18, 55, 9]
fRandInts = FluidIterable(randInts)
fRandIntsIter = fRandInts.__iter__()
# for each value in the list (outer loop)
# test against every other value in the list (inner loop)
for i in fRandIntsIter:
print(' ')
print('outer val: ', i)
innerIntsIter = fRandInts.__iter__()
for j in innerIntsIter:
innerIndex = innerIntsIter.currentIndex
# skip the element that the outloop is currently on
# because we don't want to test a value against itself
if not innerIndex == fRandIntsIter.currentIndex:
# if the test element, j, is a multiple
# of the reference element, i, then remove 'j'
if j%i == 0:
print('remove val: ', j)
# remove element in place, without breaking the
# iteration of either loop
del fRandInts[innerIndex]
# end if multiple, then remove
# end if not the same value as outer loop
# end inner loop
# end outerloop
print('')
print('final list: ', randInts)
出力と最終的な縮小リストは以下のとおりです。
outer val: 70
outer val: 20
remove val: 80
outer val: 61
outer val: 54
outer val: 18
remove val: 54
remove val: 18
outer val: 7
remove val: 70
outer val: 55
outer val: 9
remove val: 18
final list: [20, 61, 7, 55, 9]
ここでの答えのほとんどはあなたがリストのコピーを作成することを望みます。リストが非常に長く(110K項目)、代わりにリストを減らしていくほうが賢いというユースケースがありました。
まず最初に foreachループをwhileループで置き換える必要があります 、
i = 0
while i < len(somelist):
if determine(somelist[i]):
del somelist[i]
else:
i += 1
i
の値はifブロック内では変更されません。古い項目が削除されたら、同じ項目から新しい項目の値を取得したいからです。
最も効果的な方法はリストの内包表記です。多くの人が自分の主張を示します。もちろん、iterator
からfilter
を取得するのにも良い方法です。
Filter
は関数とシーケンスを受け取ります。Filter
は渡された関数を各要素に順番に適用し、関数の戻り値がTrue
またはFalse
のどちらであるかに応じて、要素を保持するか破棄するかを決定します。
例があります(タプルでオッズを取得します):
list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))
# result: [1, 5, 9, 15]
注意:イテレータも扱えません。反復子はシーケンスよりも優れていることがあります。
他の答えは正しいです、それは通常あなたが繰り返しているリストから削除するのは悪い考えです。逆反復は落とし穴を避けますが、それを行うコードに従うのははるかに難しいので、通常はリスト内包表記またはfilter
を使用することをお勧めします。
ただし、反復しているシーケンスから要素を削除しても安全な場合があります。反復している間に1つの項目のみを削除している場合です。これはreturn
またはbreak
を使って確実にすることができます。例えば:
for i, item in enumerate(lst):
if item % 4 == 0:
foo(item)
del lst[i]
break
ある条件を満たすリストの最初の項目に副作用があり、その後すぐにその項目をリストから削除するような操作をする場合、これはリストの理解よりも理解が容易です。
私はあなたの問題を解決するための3つのアプローチを考えることができます。例として、私はタプルのランダムなリストsomelist = [(1,2,3), (4,5,6), (3,6,6), (7,8,9), (15,0,0), (10,11,12)]
を作成します。私が選んだ条件はsum of elements of a Tuple = 15
です。最後のリストでは、合計が15ではないタプルだけを持つことになります。
私が選んだのは、無作為に選んだ例です。 変更しても構いません - タプルのリスト そして 条件 私が選んだもの - /
方法1> /あなたが提案したフレームワークを使う(forループの中のコードを埋める)。上記の条件を満たすTupleを削除するには、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> /与えられた条件が満たされていない要素(タプル)を含む新しいリストを作成する(これは与えられた条件が満たされたリストの要素を削除するのと同じことです)。そのためのコードは次のとおりです。
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> /与えられた条件が満たされるところのインデックスを見つけ、そしてそれらのインデックスに対応するremove要素(タプル)を使う。以下はそのためのコードです。
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よりも高速です 。方法2と方法3は、方法1よりも効率的です。 I 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]
問題は、反復中にリストから値を削除した後、リストのインデックスが折りたたまれることです。
だからあなたは代わりに理解を試すことができます。
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)
それは何よりもかなり速いはずです。
数のリストを反対にして、あなたは3で割り切れるものすべてを取り除きたい、
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)
状況によっては、リストを一度に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
このようにして、リストをコピーする必要がなくなり、理解しやすくなります。