Diese Antwort wurde ursprünglich als Antwort auf eine Frage geschrieben, die inzwischen als doppelt markiert wurde:
Entfernen von Koordinaten aus der Liste in Python
Ihr Code enthält zwei Probleme:
1) Wenn Sie remove () verwenden, versuchen Sie, Ganzzahlen zu entfernen, während Sie ein Tupel entfernen müssen.
2) Die for-Schleife überspringt Elemente in Ihrer Liste.
Lassen Sie uns durchgehen, was passiert, wenn wir Ihren 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 sowohl 'a' als auch 'b' an remove () übergeben, remove () jedoch nur ein einziges Argument akzeptiert. Wie können wir remove () dazu bringen, ordnungsgemäß mit Ihrer Liste zu arbeiten? Wir müssen herausfinden, was jedes Element Ihrer Liste ist. In diesem Fall ist jedes ein Tupel. Um dies zu sehen, greifen wir auf ein Element der Liste zu (die Indizierung beginnt bei 0):
>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>
Aha! Jedes Element von L1 ist tatsächlich ein Tupel. Das ist es, was wir übergeben müssen, um () zu entfernen. Tupel in Python sind sehr einfach. Sie werden einfach durch Einfügen von Werten in Klammern erstellt. "a, b" ist kein Tupel, aber "(a, b)" ist ein Tupel. Also ändern wir Ihren Code und führen ihn erneut aus:
# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))
Dieser Code läuft fehlerfrei, aber schauen wir uns die Liste an, die er ausgibt:
L1 is now: [(1, 2), (5, 6), (1, -2)]
Warum ist (1, -2) noch in Ihrer Liste? Es stellt sich heraus, dass das Ändern der Liste während der Verwendung einer Schleife zum Durchlaufen eine sehr schlechte Idee ist, ohne besondere Sorgfalt. Der Grund dafür, dass (1, -2) in der Liste verbleibt, besteht darin, dass sich die Positionen der einzelnen Elemente in der Liste zwischen den Iterationen der for-Schleife geändert haben. Schauen wir uns an, was passiert, wenn wir dem obigen Code eine längere Liste hinzufügen:
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 schließen können, überspringt die nächste Iteration der Schleife jedes Mal, wenn die bedingte Anweisung als wahr ausgewertet und ein Listenelement entfernt wird, die Auswertung des nächsten Elements in der Liste, da sich seine Werte jetzt an verschiedenen Indizes befinden.
Die intuitivste Lösung besteht darin, die Liste zu kopieren, dann die ursprüngliche Liste zu durchlaufen und nur die Kopie zu ändern. Sie können dies folgendermaßen versuchen:
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)
Die Ausgabe ist jedoch identisch mit zuvor:
'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]
Dies liegt daran, dass Python beim Erstellen von L2 kein neues Objekt erstellt hat. Stattdessen wurde L2 lediglich auf dasselbe Objekt wie L1 bezogen. Wir können dies mit 'is' überprüfen, das sich von lediglich "equals" (==) unterscheidet.
>>> L2=L1
>>> L1 is L2
True
Mit copy.copy () können wir eine echte Kopie erstellen. Dann funktioniert alles wie erwartet:
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 eine völlig neue Kopie von L1 erstellen zu müssen. Die Funktion 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)]
Leider kann ich nicht ausreichend beschreiben, wie reverse () funktioniert. Es gibt ein 'listreverseiterator'-Objekt zurück, wenn eine Liste an dieses übergeben wird. Aus praktischen Gründen können Sie sich vorstellen, dass eine umgekehrte Kopie des Arguments erstellt wird. Dies ist die Lösung, die ich empfehle.