Python3: For-Schleife überspringt Element der Liste?
Hallo!
Ich wollte letztens in Python (3.7.4) mit einer for-Schleife durch eine Liste gehen, um jedes Element unter einer bestimmten Bedingung aus der Liste zu löschen.
Eine stark vereinfachte Version könnte so aussehen:
l = [1,2,3,4,5]
for i in l:
____print(i)
____if i == 2: l.remove(i)
____if i == 3: l.remove(i)
print(l)
Hier möchte ich also alle Zweien und Dreien löschen. Das ganze geht natürlich effektiver, übersichtlicher und schöner, aber meine Bedingungen waren ja auch etwas komplizierter und hier geht es nur ums Prinzip.
Die Ausgabe sollte dann meinen Erwartungen entsprechend so aussehen:
1
2
3
4
5
[1,4,5]
Tatsächlich sieht sie dann aber so aus:
1
2
4
5
[1,3,4,5]
In der for-Schleife ist niemals i == 3. Das ist darauf zurückzuführen, dass durch das Löschen der 2 alle Elemente in der Liste einen Platz nach links rutschen, wobei die for-Schleife um das nächste Element durchzugehen einen Schritt weiter nach rechts geht. Dabei werden all jene Elemente übersprungen, die hinter einem zu löschenden Element kommen. Das kann man sich so zwar erklären, ist aber nicht intuitiv.
Und eingebettet in mein Programm hat die Fehlersuche ewig gedauert, wer rechnet schon damit, dass die for-Schleife ein Listenelement überspringt?
Ich wollte euch hier nur diesen interessanten Fund zeigen und euch auch nach eurer Meinung dazu fragen :)
Der beste Lösungsansatz wäre doch die list-Comprehension, oder?
Was sagt ihr dazu?
Viele Grüße! :D
3 Antworten
Das mag einem zwar komisch vorkommen, es ist aber ein dokumentiertes Verhalten:
Siehe:
Python help / The Python language reference / Compound statements / for - statement
Note
There is a subtlety when the sequence is being modified by the loop (this can only occur for mutable sequences, e.g. lists). An internal counter is used to keep track of which item is used next, and this is incremented on each iteration. When this counter has reached the length of the sequence the loop terminates. This means that if the suite deletes the current (or a previous) item from the sequence, the next item will be skipped (since it gets the index of the current item which has already been treated).
Ob du das Element vor dem remove ausgibst oder nicht, spielt keine Rolle.
Jedes mal wenn du ein Element aus der Liste entfernst ändert sich der Index der Liste und dann ist das 0te, 1te, 2te, usw. Element ein anderer als vorher.
Naja, du printest ja das i bevor du es removst. Zudem ist ein bearbeeiten einer List, durch die du gerade duchrläufst keine besonder gut idee besser wäre sowas.
l = [1,2,3,4,5]
l = [i for i in l if i not in [2,3]]
print(*l, sep='\n')
Wenn du sie überspringen willst, dann printe sie doch einfach nicht?
l = [1,2,3,4,5]
for i in l:
if i not in [2,3]:
print(i)
Ich glaube du verstehst nicht ganz. Natürlich ist die list-Comprehension klüger. Ich finde nur das Ergebnis interessant, dass Elemente der Liste übersprungen werden.