Lösche alle Dictionarries mit Value in Liste

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
BjoernLaemmerzahl
User
Beiträge: 22
Registriert: Sonntag 17. Mai 2015, 12:22

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.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

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.
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.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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.
BjoernLaemmerzahl
User
Beiträge: 22
Registriert: Sonntag 17. Mai 2015, 12:22

Ich staune jeden Tag über Python. Wahnsinn!

Vielen Dank!
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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.
BjoernLaemmerzahl
User
Beiträge: 22
Registriert: Sonntag 17. Mai 2015, 12:22

Gut zu wissen. Danke, ich werde es so verwenden.
Antworten