Iteration durch Listen

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
weasel
User
Beiträge: 5
Registriert: Sonntag 8. Februar 2009, 20:52

Sonntag 8. Februar 2009, 21:36

Hallo, ich habe so meine Probleme mit der Iteration durch Listen, und einmal ein Minimalbeispiel dazu geschrieben. Dieses Beispiel tut nicht dies, was ich von ihm erwarten würde, warum nicht?

Gegeben:
  • eine Liste mit Inhalt mehrerer anderer Listen, also eine list of lists
    eine liste von dictonarys, welche wiederum eine Liste enthalten
Was will ich erreichen:
  • Die Listen aus dem Dictonary sollen zulässige Zahlenwerte darstellen. Alle anderen Zahlenwerte, welche in der Liste mit Listen erscheinen, sollen daraus entfernt werden, und jeweils als temporär bereinigte Kopie der Liste ausgegeben werden.
Was funktioniert nicht:
  • Das erste Durchsuchen, Bereinigen und Ausgeben der Listenkopie funktioniert. Beim zweiten Durchgang jedoch scheint der Code nicht mehr eine Kopie der Ausgangsliste zu erzeugen, sondern greift auf die Liste aus dem vorherigen Durchlauf zurück
Der Code:

Code: Alles auswählen

#!/usr/bin/python

check = [{"numbers":[2,3]},{"numbers":[2,5]}]

listoflists = [[1,2,3,4,5],
              [2,3,4,5,6],
              [3,4,5,6,7],
              [4,5,6,7,8],
              [5,6,7,8,9]]

# listoflists sollte in meinem Beispiel eigentlich 2 mal durchlaufen werden. 
# Einmal sollten alle Zahlen ungleich 2 und 3 entfernt werden, die bereinigte 
# Kopie ausgegeben werden, und danach ein zweiter Durchlauf gestartet werden, 
# welcher alle Zahlen ungleich 2 und 5 entfernt.

for i in check:
    tmplistoflists = listoflists[:]

    for tmplist in tmplistoflists:
        removelist = []

        for number in tmplist:
            if number not in i['numbers']:
                removelist.append(number)

        for number in removelist:
            tmplist.remove(number)

        print "tl: ",tmplist
     print "check next"
Ich habe das Gefühl, dass es wohl irgend etwas mit dem Entfernen von Elementen aus einer Liste zu tun haben könnte. Lasse ich diesen Teil des Codes weg, funktioniert erst mal alles, wie ich es mir denke. Es wird dann natürlich aber die Liste nicht bereinigt. ;-)
Auf den Gedanken, die zu löschenden Elemente nicht gleich zu entfernen, bin ich auch erst gekommen, als ich merkte, dass Python dann offensichtlich Probleme mit dem Konstrukt "for i in list" hat, wenn während dieser Schleife aus list gelöscht wird.

Für jede Erklärung dankbar

Gruß weasel
EyDu
User
Beiträge: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Sonntag 8. Februar 2009, 21:53

Wie du schon richtig erkannt hast, darfst du die Liste, über die du iterierst, nicht direkt ändern (Elemente löschen/hinzufügen). Das kann man im allgemeinen Fall nicht sinnvoll handhaben.

Dein zweites Problem ist, dass Listen "mutable" sind. Wenn du Elemente aus einer Liste löscht oder hinzufügst, dann wird keine Kopie erzeugt, sondern diese verändert. Also erzeugst du a) eine neue Liste oder b) du kopierst sie vorher. Das machst du so:

Code: Alles auswählen

liste = [1,2,3]
kopie = liste[:]
Damit kopierst du aber nur die erste Ebene der Liste, NICHT die möglicherweise darin enthaltenen Listen. Dazu kannst du die "deepcopy"-Funktion verwenden. Ich finde es meistens jedoch einfacher, eine Liste neu zu erstellen und nicht zu kopieren.
Zuletzt geändert von EyDu am Sonntag 8. Februar 2009, 21:54, insgesamt 1-mal geändert.
Das Leben ist wie ein Tennisball.
DasIch
User
Beiträge: 2465
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Sonntag 8. Februar 2009, 21:54

Du veränderst listoflists nie und erstellst bei jedem Schleifendurchgang eine Kopie davon. Das kann nicht funktionieren.
weasel
User
Beiträge: 5
Registriert: Sonntag 8. Februar 2009, 20:52

Sonntag 8. Februar 2009, 22:02

EyDu hat geschrieben: Damit kopierst du aber nur die erste Ebene der Liste, NICHT die möglicherweise darin enthaltenen Listen. Dazu kannst du die "deepcopy"-Funktion verwenden. Ich finde es meistens jedoch einfacher, eine Liste neu zu erstellen und nicht zu kopieren.
Das geht hier aber sehr fix mit den Antworten. Genau das Deepcopy Problem war's. Anstatt [:] das Deepcopy, und schon tat der Code, was ich erwartet habe. Ich hatte ja erst einmal ein wenig im Web gesucht, bevor ich mich hier angemeldet habe. Hätte ich das mal nur eher gemacht. :-)

Vielen Dank
weasel
weasel
User
Beiträge: 5
Registriert: Sonntag 8. Februar 2009, 20:52

Sonntag 8. Februar 2009, 22:06

DasIch hat geschrieben:Du veränderst listoflists nie und erstellst bei jedem Schleifendurchgang eine Kopie davon. Das kann nicht funktionieren.
Danke auch für deine schnelle Antwort. Aber das war schon Absicht, dass ich listoflists nicht anfasse, sondern nur jeweils eine Kopie davon anfertigen wollte. Wer kann denn auch ahnen, dass er beim Kopieren nur die direkt untergordneten Elemente kopiert, und mittelbar nachgeordnete Elemente weiterhin eine Referenz auf das Originalobjekt sind. Beim nächsten mal kenne ich jedenfalls deepcopy. :-)

Gruß weasel
Antworten