Frage

Ich bin Iterieren eine Liste von Tupeln in Python über, und bin versucht, sie zu entfernen, wenn sie bestimmte Kriterien erfüllen.

for tup in somelist:
    if determine(tup):
         code_to_remove_tup

Was soll ich anstelle von code_to_remove_tup verwenden? Ich kann nicht herausfinden, wie das Produkt in dieser Art und Weise zu entfernen.

War es hilfreich?

Lösung

Sie können eine Liste Verständnis verwenden, um eine neue Liste zu erstellen, die nur die Elemente enthält, die Sie nicht entfernen möchten:

somelist = [x for x in somelist if not determine(x)]

oder durch auf die Scheibe somelist[:] zuordnen, können Sie die vorhandene Liste mutieren nur die Elemente enthalten, die Sie wollen:

somelist[:] = [x for x in somelist if not determine(x)]

Dieser Ansatz nützlich sein könnte, wenn es andere Referenzen sind, dass die Notwendigkeit, somelist die Änderungen wirksam werden.

Statt eines Verstehens, können Sie auch itertools verwenden. In Python 2:

from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)

oder in Python 3:

from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)

Andere Tipps

Die Antworten Listenkomprehensionen was darauf hindeutet, sind fast richtig - außer, dass sie eine völlig neue Liste zu erstellen und es dann den gleichen Namen geben, die alte Liste wie, sie ändern die alte Liste an seinem Platz. Das ist anders, als man durch selektive Entfernung tun würde, wie in @ Lennart Vorschlag - es ist schneller, aber wenn Ihr Liste wird über mehrere Referenzen die Tatsache zugegriffen, dass Sie nur reseating eine der Referenzen und nicht die Änderung der Liste Objekt selbst zu subtil, katastrophale Fehler führen kann.

Glücklicherweise ist es extrem einfach, sowohl die Geschwindigkeit der Liste Comprehensions und die erforderlichen Semantik von in-Place-Änderung zu erhalten - nur Code:

somelist[:] = [tup for tup in somelist if determine(tup)]

Beachten Sie den feinen Unterschied mit anderen Antworten: dies ist die Zuordnung nicht zu einem barename - es ist auf eine Liste Scheibe zuweisen, was geschieht, nur die gesamte Liste zu sein, wodurch die Liste zu ersetzen Inhalt innerhalb des gleichen Python-Liste Objekts , anstatt nur reseating eine Referenz (aus vorheriger Liste Objekt neuer Liste Objekt) wie die anderen Antworten.

Sie müssen eine Kopie der Liste nehmen und zuerst über sie iterieren, oder die Iteration wird fehlschlagen, was zu unerwarteten Ergebnissen sein kann.

Zum Beispiel (hängt davon ab, welche Art von Liste):

for tup in somelist[:]:
    etc....

Ein Beispiel:

>>> 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]

Sie müssen rückwärts sonst gehen sie ein bisschen ist der Baum-Zweig wie Absägen, die Sie sitzen auf: -)

Python 2 Benutzer: ersetzen range durch xrange zu vermeiden, eine hartcodierte Liste erstellen

Ihre beste Ansatz für ein solches Beispiel wäre eine Liste Verständnis sein

somelist = [tup for tup in somelist if determine(tup)]

In Fällen, in denen Sie etwas komplexer tun als eine determine Funktion aufrufen, ziehe ich eine neue Liste der Konstruktion und einfach zu ihm anhängt, wie ich gehen. Zum Beispiel

newlist = []
for tup in somelist:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)
somelist = newlist

Kopieren der Liste remove verwenden könnte Ihren Code schaut ein wenig sauberer machen, wie es unten in einer der Antworten beschrieben. Sie sollten auf jeden Fall diese großen Listen für extrem nicht tun, da dies die gesamte Liste Kopiert erstes beinhaltet, und auch eine O(n) remove Operation für jedes Element der Durchführung entfernt werden, so dass diese ein O(n^2) Algorithmus.

for tup in somelist[:]:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)

Offizielle Python 2 Tutorial 4.2. "Für Statements"

https://docs.python.org/2/tutorial /controlflow.html#for-statements

Dieser Teil der Dokumentation macht deutlich, dass:

  • Sie benötigen eine Kopie der iterierten Liste zu machen, ihn zu ändern
  • eine Möglichkeit, es zu tun mit der Slice-Notation [:] ist
  

Wenn Sie die Reihenfolge ändern, müssen Sie iterieren, während innerhalb der Schleife (zB ausgewählte Elemente zu duplizieren), empfiehlt es sich, zunächst eine Kopie. hat Iteration über eine Sequenz nicht implizit eine Kopie. Die Scheibe Notation macht dies besonders praktisch:

>>> 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 Dokumentation 7.3. "Die for-Anweisung"

https://docs.python.org/2/reference/compound_stmts .html # für

Dieser Teil der docs sagt noch einmal, dass Sie eine Kopie machen müssen, und gibt eine tatsächliche Entfernung Beispiel:

  

Hinweis: Es gibt eine Feinheit, wenn die Sequenz von der Schleife geändert wird (dies ist nur für veränderbare Sequenzen auftreten kann, d.h. Listen). Ein interner Zähler wird verwendet, um zu verfolgen, welches Element als nächstes verwendet wird, und dies wird bei jeder Iteration inkrementiert. Wenn diese Zähler die Länge der Folge erreicht hat, endet die Schleife. Das bedeutet, dass, wenn die Suite das aktuelle (oder vorheriges) Element aus der Sequenz löscht, wird der nächste Punkt übersprungen werden (da es den Index des aktuellen Elements erhält, die bereits behandelt wurde). Ebenso, wenn die Suite ein Element in der Sequenz vor dem aktuellen Elemente einfügt, wird das aktuelle Element wieder das nächste Mal durch die Schleife behandelt werden. Dies kann zu einem fiesen Bugs führen, indem sie eine temporäre Kopie mit einer Scheibe der gesamten Sequenz vermieden werden kann, z. B.

for x in a[:]:
    if x < 0: a.remove(x)

Allerdings stimme ich mit dieser Implementierung, da .remove() die ganze Liste durchlaufen hat , um den Wert zu finden.

Stattdessen entweder:

  • ein neues Array von Grund auf neu starten, und .append() am Ende zurück: https://stackoverflow.com/a/ 1207460/895245

    Dieses Mal effizient, aber weniger Platz effizient, weil sie eine Kopie des Arrays hält um während der Iteration.

  • Verwendung del mit einem Index: https://stackoverflow.com/a/1207485/895245

    Dies ist mehr Platz effizient, da es die Array Kopie verzichtet, aber es ist weniger Zeit effizient, weil CPython Listen ListIterator , die es kristallklar macht, dass Sie keine Liste wird wiederholt, außer mit dem Iterator selbst, und gibt Ihnen effiziente Möglichkeiten zu tun, ohne das Kopieren der Liste ändern können.

    Vielleicht ist das zugrunde liegende Prinzip ist, dass Python-Listen angenommen werden dynamische Array gesichert sein, und deshalb wird jede Art der Entfernung sowieso Zeit ineffizient sein, während Java eine schönere Interface-Hierarchie mit den beiden ArrayList und LinkedList Implementierungen von ListIterator.

    Es scheint nicht explizit verknüpfte Liste Typ in dem Python stdlib zu sein entweder: Python verlinkte Liste

Für diejenigen, die funktionale Programmierung mögen:

somelist[:] = filter(lambda tup: not determine(tup), somelist)

oder

from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))

Es könnte klug sein, um auch nur eine neue Liste zu erstellen, wenn das aktuelle Listenelement die gewünschten Kriterien erfüllt.

so:

for item in originalList:
   if (item != badValue):
        newList.append(item)

und um zu vermeiden, das gesamte Projekt mit den neuen Listen Namen neu Code:

originalList[:] = newList

Notiz, aus Python-Dokumentation:

  

copy.copy (x)   Gibt eine flache Kopie von x.

     

copy.deepcopy (x)   Gibt eine tiefe Kopie von x.

Ich brauchte dies mit einer riesigen Liste zu tun, und die Liste zu duplizieren schien teuer, zumal die Zahl der Löschungen in meinem Fall wenige würde die Elemente im Vergleich zu, die bleiben. Ich habe diesen Low-Level-Ansatz.

array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
    if someTest(array[i]):
        del array[i]
        arraySize -= 1
    else:
        i += 1

Was ich nicht weiß, ist, wie effizient ein paar Löschungen zu kopieren eine große Liste verglichen werden. Bitte kommentieren, wenn Sie keine Einsicht haben.

Diese Antwort wurde ursprünglich als Antwort auf eine Frage geschrieben, die als Duplikat markiert seitdem: Entfernen Koordinaten aus der Liste auf Python

Es gibt zwei Probleme im Code:

1) Wenn () mit entfernen, versuchen Sie ganze Zahlen zu entfernen, während Sie ein Tupel entfernen müssen.

2) Die for-Schleife wird Elemente in der Liste überspringen.

Lassen Sie uns laufen durch das, was passiert, wenn wir den Code ausführen:

>>> 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)

Das erste Problem ist, dass Sie vorbei beide ‚a‘ und ‚b‘ () zu entfernen, aber entfernen () akzeptiert nur ein einziges Argument. Wie können wir also () get remove richtig mit Ihrer Liste zu arbeiten? Wir müssen herausfinden, was jedes Element der Liste ist. In diesem Fall ist jeder ein Tupel. Um dies zu sehen, lassen Sie uns den Zugriff ein Element der Liste (Indizierung beginnt bei 0):

>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>

Aha! Jedes Element L1 ist eigentlich ein Tupel. Also das ist, was wir () werden vorbei entfernen müssen. Tupeln in Python ist sehr einfach, sie sind einfach durch Einschließen Werte in Klammern gemacht. "A, b" kein Tupel, aber "(a, b)" ist ein Tupel. Also haben wir den Code ändern und führen Sie es erneut:

# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))

Dieser Code läuft ohne Fehler, aber schauen wir uns die Liste aussehen gibt sie:

L1 is now: [(1, 2), (5, 6), (1, -2)]

Warum ist (1, -2) noch in der Liste? Es stellt sich heraus die Änderung der Liste, während eine Schleife iterieren es eine sehr schlechte Idee ohne besondere Sorgfalt. Der Grund dafür, dass (1, -2) in der Liste bleibt, ist, dass die Orte der einzelnen Elemente innerhalb der Liste zwischen Iterationen der for-Schleife verändert. Lassen Sie uns sehen, was passiert, wenn wir die oben genannten Code eine längere Liste füttern:

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)]

Wie Sie aus diesem Ergebnis ableiten können, jedes Mal, wenn die bedingte Anweisung true ergibt und ein Listenelement entfernt wird, wird die nächste Iteration der Schleife Auswertung des nächsten Elements in der Liste überspringt, weil ihre Werte nun befinden verschiedene Indizes.

Die intuitive Lösung ist die Liste zu kopieren, dann über die ursprüngliche Liste durchlaufen und nur die Kopie bearbeiten. Sie können versuchen, so wie dies zu tun:

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)

Allerdings wird die Ausgabe identisch sein vor:

'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

Das ist, weil, wenn wir L2 geschaffen, Python eigentlich nicht ein neues Objekt erstellen. Stattdessen ist es nur L2 auf das gleiche Objekt als L1 bezeichnet. Wir können dies überprüfen, mit ‚ist‘, die von nur anders „gleich“ (==).

>>> L2=L1
>>> L1 is L2
True

Wir können eine originalgetreue Kopie mit copy.copy machen (). Dann ist alles wie erwartet funktioniert:

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)]

Schließlich gibt es eine sauberere Lösung, als wenn man eine völlig neue Kopie von L1 zu machen. Die umgekehrte () Funktion:

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)]

Leider kann ich nicht ausreichend beschreiben, wie umgekehrt () funktioniert. Es gibt einen ‚listreverseiterator‘ Objekt, wenn eine Liste an sie übergeben wird. Für praktische Zwecke kann man daran denken, wie eine umgekehrte Kopie seines Arguments zu schaffen. Dies ist die Lösung, die ich empfehlen.

Wenn Sie etwas anderes während der Iteration tun wollen, kann es schön sein, sowohl den Index zu bekommen (was garantiert Sie die Lage, es zu verweisen, wenn Sie zum Beispiel eine Liste von dicts haben) und den aktuellen Liste Artikel Inhalt.

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 gibt Sie auf das Element zugreifen und den Index auf einmal. reversed ist, so dass die Indizes, die Sie gehen zu später nicht auf Sie ändern löschen Sie.

Sie könnten filter() als die eingebauten in verwendet werden sollen.

Für weitere Informationen hier überprüfen

Sie können versuchen, für Looping rückwärts so für some_list Sie etwas tun, wie:

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)

Auf diese Weise der Index ausgerichtet ist, und leidet nicht unter der Liste Aktualisierungen (unabhängig davon, ob Sie Köter Element Pop oder nicht).

Eine mögliche Lösung, nützlich, wenn Sie nicht nur einige Dinge entfernt werden sollen, sondern auch etwas tun, mit allen Elementen in einer einzigen Schleife:

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

Die meisten Antworten hier wollen Sie eine Kopie der Liste erstellen. Ich hatte einen Anwendungsfall, wo die Liste ziemlich lang war (110K Artikel), und es war klüger zu halten um die Liste zu reduzieren, statt.

Zu allererst Sie brauchen, um zu ersetzen foreach-Schleife mit while-Schleife ,

i = 0
while i < len(somelist):
    if determine(somelist[i]):
         del somelist[i]
    else:
        i += 1

Der Wert von i ist nicht im Block, wenn geändert, weil Sie Wert der neuen Position aus dem gleichen Index bekommen würden, sobald das alte Element gelöscht wird.

Ich brauchte etwas ähnliches und in meinem Fall zu tun, das Problem war, Speicher - ich mehrere Daten-Set-Objekte innerhalb einer Liste fusionieren erforderlich, nachdem er mit ihnen ein paar Sachen zu tun, als ein neues Objekt und benötigt jeder Eintrag ich loswerden zu vermeiden, wurde Verschmelzung alle von ihnen zu duplizieren und Speicher Sprengung. In meinem Fall die Objekte in einem Wörterbuch statt einer Liste mit funktionierte gut:

`` `

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:

Ich schrieb eine Bibliothek, die Sie dies tun können:

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'

Am besten ist es eine andere Methode zu verwenden, wenn möglich, das erfordert nicht Ihre iterable modifiziert, während über ihn laufen, aber für einige Algorithmen ist es vielleicht nicht, dass gerade nach vorne sein. Und so, wenn Sie sicher sind, dass Sie wirklich das Codemuster in der ursprünglichen Frage beschrieben wollen tun, es ist möglich.

Sollte auf allen wandelbar Sequenzen arbeitet nicht nur aufgelistet werden.


Vollständige Antwort:

Edit: Das letzte Codebeispiel in dieser Antwort einen für Anwendungsfall gibt Warum Sie können manchmal eine Liste an Stelle ändern mögen, anstatt eine Liste Verständnis zu verwenden. Der erste Teil der Antworten dient als Tutorial von wie ein Array kann an Ort und Stelle verändert werden.

Die Lösung folgt auf diese Antwort (für eine damit verbundene Frage) von senderle. Welche erklärt, wie das der Array-Index aktualisiert wird, während durch eine Liste iterieren, die modifiziert wurde. Die Lösung unten ist so konzipiert, um die korrekte Array-Index zu verfolgen, auch wenn die Liste geändert wird.

Download fluidIter.py von hier https://github.com/alanbacon/FluidIterator, es ist nur eine einzige Datei so git keine Notwendigkeit zu installieren. Es gibt keinen Installer, so dass Sie sicherstellen müssen, dass die Datei in der Python-Pfad ist, um sich selbst. Der Code wurde für Python 3 geschrieben und ist nicht getestet auf 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))

Dies wird erzeugt die folgende Ausgabe:

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]

Oben haben wir die pop Methode auf der Fluid Liste Objekt verwendet haben. Andere häufige iterable Verfahren sind auch wie del fluidL[i] implementiert, .remove, .insert, .append, .extend. Die Liste kann auch unter Verwendung von Scheiben geändert werden (sort und reverse Methoden sind nicht implementiert).

Die einzige Bedingung ist, dass Sie nur die Liste an Ort und Stelle ändern muss, wenn an irgendeiner Stelle fluidL oder l auf eine andere Liste Objekt zugewiesen wurden der Code nicht funktionieren würde. Das ursprüngliche fluidL Objekt würde immer noch von der for-Schleife verwendet werden, aber außerhalb des Bereichs werden würde für uns zu ändern.

d.

fluidL[2] = 'a'   # is OK
fluidL = [0, 1, 'a', 3, 4, 5, 6, 7, 8]  # is not OK

Wenn wir den aktuellen Indexwert der Liste zugreifen möchten wir nicht aufzählen können, da dies nur zählt, wie oft die for-Schleife ausgeführt wird. Stattdessen werden wir direkt das Iterator-Objekt verwenden.

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))

Dies wird Ausgang der folgende:

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]

Die FluidIterable Klasse stellt nur einen Wrapper für die ursprüngliche Liste Objekt. Das ursprüngliche Objekt kann wie so als eine Eigenschaft des Fluids Objekts zugegriffen werden:

originalList = fluidArr.fixedIterable

Weitere Beispiele / Tests können in dem if __name__ is "__main__": Abschnitt am unteren Rande des fluidIter.py finden. Es handelt sich um einen Blick wert, weil sie erklären, was in verschiedenen Situationen geschieht. Wie zum Beispiel: ein großen Teile der Liste Ersetzen einer Scheibe verwenden. Oder mit (und modifiziert) die gleiche iterable in verschachtelten for-Schleifen.

Wie ich bereits sagte, mit zu beginnen: Das ist eine komplizierte Lösung, die der Lesbarkeit des Codes verletzt und macht es zu debuggen schwieriger. Daher sind andere Lösungen wie die Liste Comprehensions in David Raznick beantworten sollte zuerst in Betracht gezogen werden. Davon abgesehen, habe ich mal gefunden, wo diese Klasse zu mir gewesen ist nützlich und hat einfacher als die Verwendung der Indizes der Elemente zu verfolgen, die zu löschen müssen.


Edit: Wie in den Kommentaren erwähnt, ist diese Antwort nicht wirklich ein Problem darstellen, für die dieser Ansatz eine Lösung zur Verfügung stellt. Ich werde versuchen, das hier zur Adresse:

Liste Comprehensions bieten eine Möglichkeit, eine neue Liste zu erzeugen, aber diese Ansätze sind in der Regel an jedem Element in isola aussehenTion, anstatt den aktuellen Stand der Liste als Ganzes.

d.

newList = [i for i in oldList if testFunc(i)]

Was aber, wenn das Ergebnis der testFunc auf den Elementen abhängt, die hinzugefügt wurden bereits newList? Oder die Elemente noch in oldList die nächsten sein könnten hinzugefügt? Es könnte noch eine Möglichkeit geben, eine Liste Verständnis zu verwenden, aber es wird beginnen, es ist Eleganz zu verlieren, und für mich fühlt es sich einfacher, eine Liste an Ort und Stelle zu ändern.

Der folgende Code ist ein Beispiel für einen Algorithmus, der aus dem obigen Problem leidet. Der Algorithmus wird eine Liste reduzieren, so dass kein Element ein Vielfaches eines anderen Elements ist.

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)

Der Ausgang und die endgültige reduzierte Liste sind unter

gezeigt
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]

Die anderen Antworten sind richtig, dass es in der Regel eine schlechte Idee ist aus einer Liste zu löschen, die Sie iterieren. Reverse Iterieren vermeidet die Gefahren, aber es ist viel schwieriger, Code zu folgen, die das tut, so in der Regel sind Sie besser dran, eine Liste Verständnis oder filter verwendet wird.

Es gibt jedoch einen Fall, in dem es sicher ist, Elemente aus einer Sequenz zu entfernen, die Sie iterieren: wenn Sie nur das Entfernen von einem Punkt, während Sie laufen. Dies kann ein return oder ein break sichergestellt werden. Zum Beispiel:

for i, item in enumerate(lst):
    if item % 4 == 0:
        foo(item)
        del lst[i]
        break

Das ist oft leichter zu verstehen als eine Liste Verständnis, wenn Sie auf das erste Element in einer Liste einige Operationen mit Nebenwirkungen tun, die einige Bedingungen erfüllt und dann das Element aus der Liste zu entfernen sofort nach.

Die effektivste Methode ist die Liste Verständnis zeigen viele Menschen ihren Fall, natürlich, es ist auch ein guter Weg, um ein iterator durch filter zu erhalten.

  

Filter erhält eine Funktion und eine Sequenz. Filter wendet die Funktion übergeben zu jedem Elemente wiederum und entscheidet dann, ob das Element zu behalten oder zu verwerfen, je nachdem, ob der Funktionsrückgabewert ist True oder False.

Es ist ein Beispiel (die Chancen im Tupel erhalten):

list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))  
# result: [1, 5, 9, 15]

Achtung: Sie können auch nicht Iteratoren behandeln. Iteratoren sind manchmal besser als Sequenzen.

kann ich denke an drei Ansätze Ihr Problem zu lösen. Als Beispiel werde ich eine zufällige Liste von Tupeln somelist = [(1,2,3), (4,5,6), (3,6,6), (7,8,9), (15,0,0), (10,11,12)] erstellen. Die Bedingung, dass ich wählen ist sum of elements of a tuple = 15. In der definitiven Liste haben wir nur die Tupel, deren Summe auf 15

nicht gleich

Was ich gewählt habe, ist ein zufällig ausgewähltes Beispiel. Fühlen Sie sich frei zu ändern, die Liste von Tupeln und Bedingung , dass ich gewählt haben.

Methode 1.> Verwenden Sie den Rahmen, den Sie vorgeschlagen hatte (wo man innerhalb einer for-Schleife in einem Code füllt). Ich verwende einen kleinen Code mit del ein Tupel zu löschen, die die genannte Bedingung erfüllt. Jedoch wird dieses Verfahren ein Tupel verpassen (die die genannte Bedingung genügt), wenn zwei hintereinander platziert Tupeln die gegebene Bedingung erfüllen.

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)]

Methode 2.> , um eine neue Liste Construct die Elemente (Tupel) enthält, in denen die angegebene Bedingung nicht erfüllt ist (dies ist das gleiche wie Elemente der Liste zu entfernen, wo die vorgegebene Bedingung erfüllt ist). Im Folgenden ist der Code für das:

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)]

Methode 3.> finden, wo die Indizes gegebene Bedingung erfüllt ist, und verwendet dann entfernen Elemente (Tupel) zu diesem Indizes entsprechen. Im Folgenden ist der Code für das.

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)]

Methode 1 und Methode 2 sind schneller als Verfahren 3 . Method2 und method3 sind effizienter als method1. I bevorzugen method2 . Für das oben genannte Beispiel time(method1) : time(method2) : time(method3) = 1 : 1 : 1.7

for-Schleife wird durch Index laufen werden ..

Sehen Sie eine Liste haben,

[5, 7, 13, 29, 65, 91]

Sie haben mit Listenvariable namens lis. und Sie mit demselben zu entfernen ..

Ihre Variable

lis = [5, 7, 13, 29, 35, 65, 91]
       0  1   2   3   4   5   6

während der 5. Iteration

Nummer 35 war keine Primzahl, so dass Sie aus einer Liste entfernt.

lis.remove(y)

und dann nächster Wert (65) gehen Sie zum vorherigen Index.

lis = [5, 7, 13, 29, 65, 91]
       0  1   2   3   4   5

so vierte Iteration gemacht Zeiger auf der 5th bewegt ..

das ist, warum Ihre Schleife tut Abdeckung 65 seit seinem bewegte in vorherigen Index.

Sie sollten also nicht die Liste in einer anderen Variable verweisen, die noch original statt Kopie verweisen.

ite = lis #dont do it will reference instead copy

so tut Kopie der Liste mit list[::]

Sie jetzt wird es geben,

[5, 7, 13, 29]

Problem ist, dass Sie einen Wert aus einer Liste während der Iteration dann Listenindex kollabieren entfernt.

So können Sie Verständnis versuchen statt.

, die unterstützt alle iterable wie, Liste, Tupel, dict, string etc

Für alles, was das Potenzial wirklich groß sein muss, verwende ich die folgende.

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)

Das sollte deutlich schneller sein als alles andere.

In einigen Situationen, in denen Sie mehr tun, als nur Filtern einer Liste ein Element zu der Zeit, mögen Sie Ihre Iteration während Iterieren ändern.

Hier ist ein Beispiel, in dem das Kopieren der Liste vorher falsch ist, Reverse Iteration ist unmöglich, und eine Liste Verständnis ist auch keine Option.

""" 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

Wenn Sie die neue Liste später verwenden, können Sie einfach die Elem auf Keine setzen, und richten sie dann in der späteren Schleife, wie dies

for i in li:
    i = None

for elem in li:
    if elem is None:
        continue

Auf diese Weise Sie dont't müssen die Liste kopieren und es ist leichter zu verstehen.

uppose eine Liste der Anzahl und Sie entfernen möchten alle nicht, die durch 3 teilbar ist,

list_number =[i for i in range(100)]

list comprehension verwenden, dies wird eine neue Liste careate und neuen Speicherplatz erstellen

new_list =[i for i in list_number if i%3!=0]

lambda filter Funktion verwendet, wird diese resultierende neue Liste erstellen und memeory Raum verbrauchen

new_list = list(filter(lambda x:x%3!=0, list_number))

ohne Speicherplatz für neue Liste raubend und modifizieren bestehende Liste

for index, value in enumerate(list_number):
    if list_number[index]%3==0:
        list_number.remove(value)

Sogleich wollen Sie eine Kopie der Liste zu erstellen, so dass Sie, dass als Referenz haben können, wenn Sie durchlaufen und Tupel in dieser Liste, die erfüllen ein bestimmten Kriterien zu löschen.

Dann hängt es davon ab, welche Art von Liste, die Sie die Ausgabe wollen, ob das eine Liste der entfernten Tupel oder eine Liste der Tupel, die nicht entfernt werden.

Wie David wies darauf hin, empfehle ich Liste Verständnis um die Elemente zu halten Sie nicht wollen, zu entfernen.

somelist = [x for x in somelist if not determine(x)]
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top