Wenn wir die Reihenfolge der Elemente beibehalten wollen, wie wäre es damit:
used = set()
mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = [x for x in mylist if x not in used and (used.add(x) or True)]
Und eine weitere Lösung mit reduce
und ohne die vorübergehende used
var.
mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])
UPDATE - Dez, 2020 - Vielleicht der beste Ansatz!
Ab Python 3.7 wird der Standard Diktat behält die Einfügereihenfolge bei.
Geändert in Version 3.7: Die Reihenfolge der Wörterbücher ist garantiert die Einfügereihenfolge. Dieses Verhalten war ein Implementierungsdetail von CPython aus Version 3.6.
Dies gibt uns also die Möglichkeit, die dict.from_keys
für die Deduplizierung!
HINWEIS: Die Credits gehen an @rlat dass Sie uns diesen Ansatz in den Kommentaren mitgeteilt haben!
mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = list(dict.fromkeys(mylist))
In Bezug auf die Geschwindigkeit - für mich ist es schnell genug und lesbar genug, um mein neuer Lieblingsansatz zu werden!
UPDATE - März, 2019
Und eine 3. Lösung, die ganz nett ist, aber etwas langsam, da .index
ist O(n).
mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = [x for i, x in enumerate(mylist) if i == mylist.index(x)]
UPDATE - Okt, 2016
Eine weitere Lösung mit reduce
aber dieses Mal ohne .append
was sie für den Menschen lesbarer und verständlicher macht.
mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
unique = reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])
#which can also be writed as:
unique = reduce(lambda l, x: l if x in l else l+[x], mylist, [])
HINWEIS: Denken Sie daran, dass das Skript umso weniger leistungsfähig ist, je besser es für den Menschen lesbar ist. Ausgenommen sind lediglich die dict.from_keys
Ansatz, der spezifisch für Python 3.7+ ist.
import timeit
setup = "mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']"
#10x to Michael for pointing out that we can get faster with set()
timeit.timeit('[x for x in mylist if x not in used and (used.add(x) or True)]', setup='used = set();'+setup)
0.2029558869980974
timeit.timeit('[x for x in mylist if x not in used and (used.append(x) or True)]', setup='used = [];'+setup)
0.28999493700030143
# 10x to rlat for suggesting this approach!
timeit.timeit('list(dict.fromkeys(mylist))', setup=setup)
0.31227896199925453
timeit.timeit('reduce(lambda l, x: l.append(x) or l if x not in l else l, mylist, [])', setup='from functools import reduce;'+setup)
0.7149233570016804
timeit.timeit('reduce(lambda l, x: l+[x] if x not in l else l, mylist, [])', setup='from functools import reduce;'+setup)
0.7379565160008497
timeit.timeit('reduce(lambda l, x: l if x in l else l+[x], mylist, [])', setup='from functools import reduce;'+setup)
0.7400134069976048
timeit.timeit('[x for i, x in enumerate(mylist) if i == mylist.index(x)]', setup=setup)
0.9154880290006986
BEANTWORTUNG VON KOMMENTAREN
Denn @monica hat eine gute Frage gestellt: "Wie funktioniert das?". Für alle, die Probleme haben, es herauszufinden. Ich werde versuchen, eine tiefere Erklärung darüber zu geben, wie dies funktioniert und welche Zauberei hier passiert ;)
Also fragte sie zuerst:
Ich versuche zu verstehen, warum unique = [used.append(x) for x in mylist if x not in used]
funktioniert nicht.
Nun, es funktioniert tatsächlich
>>> used = []
>>> mylist = [u'nowplaying', u'PBS', u'PBS', u'nowplaying', u'job', u'debate', u'thenandnow']
>>> unique = [used.append(x) for x in mylist if x not in used]
>>> print used
[u'nowplaying', u'PBS', u'job', u'debate', u'thenandnow']
>>> print unique
[None, None, None, None, None]
Das Problem ist, dass wir innerhalb des Systems nicht die gewünschten Ergebnisse erzielen. unique
Variable, jedoch nur innerhalb der used
variabel. Der Grund dafür ist, dass während des Verstehens der Liste .append
used
Variable und gibt zurück None
.
Um also die Ergebnisse in die unique
Variable, und verwenden Sie trotzdem die gleiche Logik mit .append(x) if x not in used
müssen wir dies verschieben .append
auf der rechten Seite des Listenverständnisses aufrufen und einfach zurückgeben x
auf der linken Seite.
Aber wenn wir zu naiv sind und uns einfach darauf verlassen:
>>> unique = [x for x in mylist if x not in used and used.append(x)]
>>> print unique
[]
Wir werden nichts zurückbekommen.
Auch hier ist der Grund, dass die .append
Methode gibt zurück None
, und das gibt unserem logischen Ausdruck das folgende Aussehen:
x not in used and None
Das wird im Grunde immer so sein:
- wertet aus zu
False
wenn x
ist in used
,
- wertet aus zu
None
wenn x
ist nicht in used
.
Und in beiden Fällen ( False
/ None
), wird dies behandelt als falsy
Wert und wir erhalten eine leere Liste als Ergebnis.
Aber warum wird das so bewertet None
wenn x
ist nicht in used
? Jemand könnte fragen.
Nun, das liegt daran, dass Python auf diese Weise Kurzschluss Betreiber Werke .
Der Ausdruck x and y
wertet zunächst x aus; wenn x falsch ist, ist sein Wert zurückgegeben; andernfalls wird y ausgewertet und der resultierende Wert wird zurückgegeben.
Wenn also x
wird nicht verwendet (d.h. wenn seine True
) der nächste Teil oder der Ausdruck wird ausgewertet ( used.append(x)
) und sein Wert ( None
) zurückgegeben werden.
Aber das ist es, was wir wollen, um die eindeutigen Elemente aus einer Liste mit Duplikaten zu erhalten, wollen wir .append
Sie werden erst dann in eine neue Liste aufgenommen, wenn sie zum ersten Mal auftauchen.
Wir wollen also wirklich bewerten used.append(x)
nur wenn x
ist nicht in used
Vielleicht gibt es eine Möglichkeit, dies zu ändern. None
Wert in eine truthy
einer wird es uns doch gut gehen, oder?
Nun, ja, und hier ist der 2. Typ von short-circuit
Die Betreiber kommen zum Spielen.
Der Ausdruck x or y
wertet zunächst x aus; wenn x wahr ist, ist sein Wert zurückgegeben; andernfalls wird y ausgewertet und der resultierende Wert wird zurückgegeben.
Wir wissen, dass .append(x)
wird immer falsy
Wenn wir also nur eine or
neben ihm, werden wir immer den nächsten Teil bekommen. Das ist der Grund, warum wir schreiben:
x not in used and (used.append(x) or True)
so können wir bewerten used.append(x)
und erhalten True
als Ergebnis, nur wenn der erste Teil des Ausdrucks (x not in used)
est True
.
Ähnlich verhält es sich beim 2. Ansatz mit der reduce
Methode.
(l.append(x) or l) if x not in l else l
#similar as the above, but maybe more readable
#we return l unchanged when x is in l
#we append x to l and return l when x is not in l
l if x in l else (l.append(x) or l)
wo wir:
- Anhängen
x
a l
und geben das l
wenn x
ist nicht in l
. Dank der or
Anweisung .append
wird ausgewertet und l
wird danach zurückgegeben.
- Rückkehr
l
unangetastet, wenn x
ist in l