for-Schleife funktioniert nicht wie erwartet

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Azimoth
User
Beiträge: 8
Registriert: Sonntag 1. Juli 2012, 16:14

Ich versuche mich mal wieder an einem Project Euler Problem... und scheitere.

Diesmal will ich eine Liste erstellen in der jede Kombination einer 4-stelligen Zahl aufgelistet ist (also 1234, 2341, 3412, 4123 etc).
Der Teil klappt ganz prima.
Im nächsten Schritt sollen dann alle zahlen die keine Primzahlen sind aus der Liste entfernt werden.
Und dabei hakts.

Ich gedachte das ganze mit einer for-Schleife zu machen, siehe hier:

Code: Alles auswählen

    print(kombinationen)

    for jede_zahl in kombinationen:
        print(jede_zahl)
        if primzahl_check(jede_zahl) != True:
            kombinationen.remove(jede_zahl)
            print("raus")

    print(kombinationen)
und erhalte als Output:
[1000]
1000
raus
[]
[1001, 1010, 1100]
1001
raus
1100
raus
[1010]
[1002, 1020, 1200, 2100, 2010, 2001]
1002
raus
1200
raus
2010
raus
[1020, 2100, 2001]
...
erst dachte ich meine (selbstgebastelte) Primzahl-Abfrage funktioniert nicht richtig, aber dann fiel mir auf, dass garnicht alle Zahlen in der Liste überprüft werden.

Beispielsweise:
aus der Liste "[1001, 1010, 1100]" werden nur "1001" und "1100" aufgerufen (und überprüft). "1010" bleibt einfach so in der Liste, weil es dem Primzahlen-Check garnicht erst unterzogen wird.
In den darauf folgenden Listen läuft es ganz ähnlich: Es wird scheinbar nur jede zweite Zahl überprüft.

Wie kommt das? Und wie behebe ich es?

EDIT: Python3.2, das vergaß ich zu erwähnen.
Zuletzt geändert von Azimoth am Dienstag 24. Juli 2012, 12:35, insgesamt 1-mal geändert.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Man sollte *niemals-nie* (das meine ich jetzt wirklich ernst) während des Iterierens (z.B. in einer `for`-Schleife) Objekte entfernen. Du solltest vielmehr die passenden Objekte in einer neuen Liste sammeln, anstatt die Original-Liste zu verändern. Das geht z.B. auch recht kompakt über eine List Comprehension.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du darfst nicht mit for über eine Liste iterieren und daraus Elemente löschen. Am besten legst du also einfach eine neue Liste an:

Code: Alles auswählen

filtered = [x for x in kombinationen if primzahl_check(x)]
Oder natürlich der übliche Weg über append.

Wenn du irgendwas mit ==True, !=True (oder entsprechend mit False) vergleichst, dann ist das überflüssig. Statt ``x == True`` kannst du gleich ``x`` schreiben. x ist bereits ein Wahrheitswert, bei einem Vergleich mit ==True kommt nur wieder x raus. ``x != True`` solltest du besser als ``not x`` schreiben.

Auch deine Namenswahl ist schlecht: in "jede_zahl" steckt nicht jede Zahl drin, sondern genau eine Zahl aus "Kombinationen". Außerdem ist es sinnvoll, Funktionen in Form von Verben zu bennen. Statt "primzahl_check" also besser "ist_prim". Dann solltest du dir auch abgewöhnen deutsche und entlische Namen durcheinander zu mischen. Entscheide dich einfach für eine Sprache. Am gebräuchlichsten ist natürlich Englisch.

Edit: Da hat sich ein falsches "not" eingeschlichen.
Zuletzt geändert von EyDu am Dienstag 24. Juli 2012, 13:04, insgesamt 1-mal geändert.
Das Leben ist wie ein Tennisball.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Azimoth hat geschrieben:Es wird scheinbar nur jede zweite Zahl überprüft.
Stelle dir das so vor: Python merkt sich die Position, wo das aktuell behandelte Objekt innerhalb der Liste liegt. Sagen wir mal, es liegt an Position 1. Der nächste Schritt wäre dann logischerweise das Objekt an Position 2, usw. Wenn du nun aber Position 1 aus der Liste entfernst, dann rutscht das Element auf Position 2 um eins nach vorne - also auf Position 1. Python denkt aber weiterhin, dass es als nächstes die Position 2 nehmen muss. An dieser Stelle ist jetzt jedoch das Objekt, was ursprünglich auf Position 3 lag (ich hoffe du kannst mir folgen). Dadurch wird das von 2 auf 1 gerutschte Objekte übersprungen und es tritt in etwa der Effekt ein, den du beschreibst.
Azimoth
User
Beiträge: 8
Registriert: Sonntag 1. Juli 2012, 16:14

Vielen Dank, andersherum (also if primzahl == True: append...) klappt es.

@Snafu: Danke, da hätte man wirklich drauf kommen können... bin ich aber erst als ich überlegt habe wo der Unterschied zwischen der (funktionierenden) .append()-Variante und der .remove() Variante liegt.

@EyDu: aber mit "for jede_zahl in kombinationen" wird für jede Zahl in (der Liste) Kombinationen geprüft ob's Primzahlen sind. ;)
Ich erkenne aber deinen Punkt. Und natürlich macht es auch Sinn sich das schonmal anzugewöhnen, auch wenn man die Programme nie veröffentlichen wird. (Kann ja mal wichtig werden.)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Azimoth hat geschrieben:Vielen Dank, andersherum (also if primzahl == True: append...) klappt es.
Nun liest du dir meinen Beitrag zum Thema "== True" direkt noch einmal durch. Kürzer ginge übrigens noch:

Code: Alles auswählen

kombinationen = filter(ist_prim, kombinationen)
Azimoth hat geschrieben:@EyDu: aber mit "for jede_zahl in kombinationen" wird für jede Zahl in (der Liste) Kombinationen geprüft ob's Primzahlen sind. ;)
Das ist klar, aber bei jedem Durchlauf enthält "jede_zahl" GENAU EINE Zahl aus der Liste der Kombinationen. Und wichtig ist nur, was aktuell an den Namen gebunden ist und nicht, was über einen Zeitraum alles passiert.
Das Leben ist wie ein Tennisball.
Antworten