Seite 1 von 2
Doppelte Elemente einer Liste elegant entfernen
Verfasst: Dienstag 28. Oktober 2008, 19:09
von numerix
Wie würdet ihr die Elemente einer Liste, die doppelt vorkommen, entfernen?
Nein, ich meine nicht die Reduktion auf je ein Exemplar pro Element (also z.B. über Umwandlung in ein set), sondern die vollständige Entfernung dieser Elemente, so dass nur noch die Elemente übrigbleiben, die einmalig waren.
Konkret handelt es sich bei den Listenelementen um Tupel mit Zahlenwerten.
Meine erste Lösung sieht so aus, dass ich ein set der Liste anfertige, dieses durchlaufe und prüfe, ob die Anzahl der einzelnen Elemente in der Liste größer als 1 ist. Wenn ja, werden sie aus der Liste entfernt. Funktional einwandfrei.
ABER: Ist nicht elegant. Wie kann man das schöner lösen? (Performance ist nicht das Problem. Die Liste ist nicht lang.)
Verfasst: Dienstag 28. Oktober 2008, 19:26
von BlackJack
Ungetestet:
Code: Alles auswählen
histogram = defaultdict(int)
for item in list_a:
histogram[item] += 1
result = [x for x in list_a if histogram[x] == 1]
Erhält sogar die Reihenfolge der Werte aus `list_a`.
Verfasst: Dienstag 28. Oktober 2008, 19:48
von Y0Gi
Jop, schließe mich BlackJack an; ``collections.defaultdict`` war mein erster Gedanke.
Alternativ vielleicht von ``set`` (oder gleich ``list``) so ableiten, dass ``add()`` (bzw. ``__setitem__()``[?]) bei der Anweisung, ein bereits vorhandenes Element hinzuzufügen, dieses direkt löscht und das übergebene Element verwirft. Je nachdem, in welchem Umfang du das nutzen willst.
Verfasst: Dienstag 28. Oktober 2008, 20:49
von lunar
Y0Gi hat geschrieben:Alternativ vielleicht von ``set`` (oder gleich ``list``) so ableiten, dass ``add()`` (bzw. ``__setitem__()``[?]) bei der Anweisung, ein bereits vorhandenes Element hinzuzufügen, dieses direkt löscht und das übergebene Element verwirft. Je nachdem, in welchem Umfang du das nutzen willst.
Dann benötigt man aber ein "set" im "set", um die Liste der bereits verworfenen Elemente zu speichern. Ansonsten führt nämlich der dritte "set.add()" Aufruf dazu, dass das Element wieder hinzugefügt wird.
Verfasst: Dienstag 28. Oktober 2008, 22:35
von numerix
Vielen Dank für eure Vorschläge. Die Idee mit dem dictionary ist interessant.
Die Ausführungen von Y0Gi haben noch eine andere Erleuchtung mit sich gebracht: Da die besagte Liste zuvor vom Programm selbst erzeugt wird, und zwar sukzessive via append, ist es natürlich am schlauesten, ein schon vorhandenes Element gar nicht erst erneut anzuhängen, sondern das schon vorhandene stattdessen zu löschen ...
Verfasst: Mittwoch 29. Oktober 2008, 12:54
von Y0Gi
lunar: Guter Einwand, bei einem allgemeineren Szenario (Elemente können auch mehr als zweimal vorkommen) muss man natürlich eine Liste der Duplikate führen.
Verfasst: Donnerstag 29. Januar 2009, 16:51
von numerix
Ups, Spam zitiert - jetzt entfernt.
Verfasst: Donnerstag 29. Januar 2009, 16:56
von lunar
Spam ...
Verfasst: Donnerstag 29. Januar 2009, 16:56
von hendrikS
Eine Kombination aus set, count und remove sollte auch zum Erfolg fuehren.
Verfasst: Donnerstag 29. Januar 2009, 17:19
von Leonidas
User + Posting gelöscht, aber durch das Zitat ist der Spam immer noch da...
numerix hat geschrieben: 
Was ich mich ja frage, warum zitiert man denn Spam?
Edit: Danke fürs ausbessern, numerix.
Verfasst: Donnerstag 29. Januar 2009, 17:33
von hendrikS
Hier meine Lösung:
Code: Alles auswählen
a = [3,4,3,5,3,2,2,1]
print [i for i in set(a) if a.count(i)<2]
Aber ich denke, es ist Jacke wie Hose. BlackJacks ist auch nicht schlecht.
Verfasst: Donnerstag 29. Januar 2009, 17:48
von HWK
@hendrikS: Deins ist zwar weniger Quellcode, dürfte bei langen Listen aber deutlich länger brauchen, da count() die Liste ja jedesmal neu durchlaufen muss.
MfG
HWK
Verfasst: Donnerstag 29. Januar 2009, 17:54
von HerrHagen
Das set brauchts in dem Code von hendrikS nich.
Code: Alles auswählen
>>> a = [3,4,3,5,3,2,2,1]
>>> [i for i in a if a.count(i)<2]
[4, 5, 1]
So bleibt auch die Reihenfolge gewahrt.
Find ich persönlich viel eleganter als die defaultdict Variante.
EDIT: @HWK: Ich denk auf Zeit kommts nicht an?
Verfasst: Donnerstag 29. Januar 2009, 17:56
von numerix
Leonidas hat geschrieben:User + Posting gelöscht, aber durch das Zitat ist der Spam immer noch da...
numerix hat geschrieben: 
Was ich mich ja frage, warum zitiert man denn Spam?
Ich dachte tatsächlich, der hätte sich was dabei gedacht ...
Im übrigen war das ursprüngliche Problem in diesem Thread schon gelöst ...
Verfasst: Donnerstag 29. Januar 2009, 17:58
von HerrHagen
oh, ich seh grad - ist schon etwas länger her...
Verfasst: Donnerstag 29. Januar 2009, 17:59
von keppla
HWK hat geschrieben:@hendrikS: Deins ist zwar weniger Quellcode, dürfte bei langen Listen aber deutlich länger brauchen, da count() die Liste ja jedesmal neu durchlaufen muss.
Das mag stimmen, aber premature optimisation is the root of all evil und so. Ich hab jüngst erst festgestellt, dass einer meiner algorithmen durchs (ineffiziente) stringaneinanderkleben gar nicht so sehr verlangsamt wurde wie durch meine Optimierungsansätze.
Verfasst: Donnerstag 29. Januar 2009, 18:00
von gkuhl
numerix hat geschrieben:Ups, Spam zitiert - jetzt entfernt.
So einen kleinen fleißigen Bot, der häufige Anfängerfragen beanwortet, würde sich hier im Forum auch ganz hübsch machen.

Verfasst: Donnerstag 29. Januar 2009, 18:24
von n4p
Der müsste ja quasi nur die Ergebnisse der Suche als Link posten wenn möglichst viele Worte aus der Anfrage oft gefunden werden.
Wer das ohne false positives hinbekommt kann sich da ja mal dran machen

Verfasst: Donnerstag 29. Januar 2009, 18:38
von hendrikS
numerix hat geschrieben:
Im übrigen war das ursprüngliche Problem in diesem Thread schon gelöst ...
Ich fände es gut, wenn ein Problem gelöst ist, es auch als solches zu markieren. Hat mich nicht viel Zeit gekostet.
Verfasst: Donnerstag 29. Januar 2009, 19:17
von Leonidas
hendrikS hat geschrieben:Ich fände es gut, wenn ein Problem gelöst ist, es auch als solches zu markieren. Hat mich nicht viel Zeit gekostet.
Ich fände es schlecht und das wurde auch schon mehrfach diskutiert. Die Nachteile des "gelöst" markierens überwiegen.