Doppelte Elemente einer Liste elegant entfernen

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.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

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.)
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`.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

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.
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.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

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 ...
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

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.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Ups, Spam zitiert - jetzt entfernt.
Zuletzt geändert von numerix am Donnerstag 29. Januar 2009, 17:55, insgesamt 1-mal geändert.
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Eine Kombination aus set, count und remove sollte auch zum Erfolg fuehren.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
Zuletzt geändert von Leonidas am Donnerstag 29. Januar 2009, 17:57, insgesamt 1-mal geändert.
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

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.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

@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
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

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?
Zuletzt geändert von HerrHagen am Donnerstag 29. Januar 2009, 17:56, insgesamt 1-mal geändert.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

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 ... :oops:

Im übrigen war das ursprüngliche Problem in diesem Thread schon gelöst ...
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

oh, ich seh grad - ist schon etwas länger her...
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

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.
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

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. 8)
n4p
User
Beiträge: 55
Registriert: Dienstag 10. Juni 2008, 11:05

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 :)
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

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.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
Antworten