Seite 1 von 1

Lösche alle Dictionarries mit Value in Liste

Verfasst: Dienstag 18. August 2015, 13:04
von BjoernLaemmerzahl
Hallo,

Ich stolpere leider mit meinen Anfängerschuhen wieder über ein Problem.

Wenn ich schauen will ob Werte aus Liste A in Liste B vorhanden ist benuzte ich:

Code: Alles auswählen

output= [x for x in listeAif x not in ListeB]
Ich habe nun eine Liste von Dictionaries mit folgenden Keys:

Code: Alles auswählen

KEYS = ["Name", "Date Start", "Date End", "Availability", "Status"]
Ich möchte nun alle Dictionaries entfernen bei denen "Name" einem Wert aus der Liste selector entspricht.

Mein erster Gedanke sieht so aus:

plants .... Liste mit Dictionaries
selector ... Liste mit Werten welche gelöscht werden soll.

Code: Alles auswählen

        for i in xrange(0, len(plants)):
            print "Length:", len(plants)
            print "i",i
            try:
                if plants[i].get("Name", "Missing") in  selector:
                    print "Found"
                else:
                    print plants[i].get("Name", "Missing")
                    print "Deleting..."
                    del plants[i]
            except IndexError:
                print "index error"
Leider werden aber nicht alle Dictionaries gelöscht, sondern nur die Hälfte. Ich schätze, dass dies deshalb geschieht weil Einträge aus der gleichen Liste lösche über die meine Schleife läüft.
Ich kann "i" nicht einfach "zurücksetzen", da eine Loop nicht, wir bei VBA, einfach erhöht wird.

Re: Lösche alle Dictionarries mit Value in Liste

Verfasst: Dienstag 18. August 2015, 13:18
von cofi
Das ganze funktioniert viel einfacher, wenn du das Problem umdrehst: Behalte alle passenden Dictionaries (in einer neuen Liste).

Mit einer List Comprehension:

Code: Alles auswählen

plants  = [{...},{...}]
selectors = []

cleaned_plants = [d for d in plants
                  if d.get("Name", None) in selector]
Daneben: Ueber die Indizes einer Liste zu iterieren ist ein Anti-Pattern in Python, da du meistens sowieso die Elemente haben willst. Wenn du _zusaetzlich_ die Indizes brauchst, gibt es die `enumerate` Funktion.

Re: Lösche alle Dictionarries mit Value in Liste

Verfasst: Dienstag 18. August 2015, 13:27
von BlackJack
@BjoernLaemmerzahl: Noch als Anmerkung: ``in``/``not in`` mit einer Liste als rechtem Operanden durchsucht diese Liste linear, also Elemenet für Element. Das kann leicht sehr ineffizient werden. Dafür gibt es den `set`-Typ wo der Test mit ``in``/``not in`` in konstanter Zeit erfolgt.

Re: Lösche alle Dictionarries mit Value in Liste

Verfasst: Dienstag 18. August 2015, 13:42
von snafu
Ich schließe mich cofi an: Das Erzeugen einer *neuen* Datenstruktur, in der man diejenigen Objekte ablegt, die man behalten möchte, ist meistens die bessere Idee. Das `None` kann man bei `get()` übrigens weglassen:

Code: Alles auswählen

result = [p for p in plants if p.get('Name') in selectors]
Für Wörterbücher, die den Schlüssel "Name" *nicht* enthalten, wird dann automatisch `None` zurückgeliefert. Hierdurch kann man das Prüfen auf Vorhandensein des Schlüssel und das Prüfen des Schlüsselwertes sozusagen in einem Rutsch erledigen. Diese Variante funktioniert selbstverständlich nur dann erwartungsgemäß, wenn in `selectors` selbst kein `None` enthalten ist.

Re: Lösche alle Dictionarries mit Value in Liste

Verfasst: Dienstag 18. August 2015, 13:47
von BjoernLaemmerzahl
Ich staune jeden Tag über Python. Wahnsinn!

Vielen Dank!

Re: Lösche alle Dictionarries mit Value in Liste

Verfasst: Dienstag 18. August 2015, 13:54
von snafu
Und um BlackJacks Anmerkung etwas anschaulicher auszuführen: Wenn man die Auswahlkriterien so schreibt:

Code: Alles auswählen

selectors = {'spam', 'ham', 'eggs'}
...dann legt Python ein `set` an. Hierdurch erlangt man insbesondere bei sehr vielen `plants` und/oder einer großen Anzahl an `selectors` in aller Regel einen Performancegewinn, weil Elemente mithilfe dieser Datenstruktur schneller wiedergefunden werden können als mit einer Liste.

Re: Lösche alle Dictionarries mit Value in Liste

Verfasst: Dienstag 18. August 2015, 14:12
von BjoernLaemmerzahl
Gut zu wissen. Danke, ich werde es so verwenden.