1191 Stimmen

Eindeutige Werte aus einer Liste in Python abrufen

Ich möchte die eindeutigen Werte aus der folgenden Liste abrufen:

['nowplaying', 'PBS', 'PBS', 'nowplaying', 'job', 'debate', 'thenandnow']

Die Ausgabe, die ich benötige, ist:

['nowplaying', 'PBS', 'job', 'debate', 'thenandnow']

Dieser Code funktioniert:

output = []
for x in trends:
    if x not in output:
        output.append(x)
print(output)

Gibt es eine bessere Lösung, die ich verwenden sollte?

1473voto

lefterav Punkte 14253

Deklarieren Sie zunächst Ihre Liste ordnungsgemäß, getrennt durch Kommata. Sie können die eindeutigen Werte erhalten, indem Sie die Liste in eine Menge umwandeln.

mylist = ['nowplaying', 'PBS', 'PBS', 'nowplaying', 'job', 'debate', 'thenandnow']
myset = set(mylist)
print(myset)

Wenn Sie es weiter als Liste verwenden, sollten Sie es wieder in eine Liste umwandeln, indem Sie dies tun:

mynewlist = list(myset)

Eine andere Möglichkeit, die wahrscheinlich schneller wäre, wäre die Verwendung eines Sets von Anfang an, anstatt einer Liste. Dann sollte Ihr Code sein:

output = set()
for x in trends:
    output.add(x)
print(output)

Wie bereits erwähnt, wird die ursprüngliche Ordnung durch die Sets nicht aufrechterhalten. Wenn Sie das brauchen, sollten Sie nach einem Bestellmenge Implementierung (siehe diese Frage für mehr).

465voto

alemol Punkte 7050

Um mit dem Typ, den ich verwenden würde, konsistent zu sein:

mylist = list(set(mylist))

227voto

Todor Punkte 14019

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:

  1. wertet aus zu False wenn x ist in used ,
  2. 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:

  1. 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.
  2. Rückkehr l unangetastet, wenn x ist in l

121voto

Nicolas Barbey Punkte 6499

Eine Python-Liste:

>>> a = ['a', 'b', 'c', 'd', 'b']

Um einzigartige Gegenstände zu erhalten, wandeln Sie sie einfach in ein Set um (das Sie bei Bedarf wieder in eine Liste umwandeln können):

>>> b = set(a)
>>> print(b)
{'b', 'c', 'd', 'a'}

111voto

Samuele Mattiuzzo Punkte 10548

Welcher Typ ist Ihre Ausgangsvariable?

Python setzt sind das, was Sie brauchen. Deklarieren Sie die Ausgabe wie folgt:

output = set()  # initialize an empty set

und Sie sind bereit, Elemente mit output.add(elem) und stellen Sie sicher, dass sie einzigartig sind.

Achtung: Sets behalten NICHT die ursprüngliche Reihenfolge der Liste bei.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X