623 Stimmen

Sortieren einer Liste anhand von Werten aus einer anderen Liste

Ich habe eine solche Liste von Zeichenfolgen:

X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0,   1,   1,   0,   1,   2,   2,   0,   1 ]

Was ist der kürzeste Weg, X anhand der Werte von Y zu sortieren, um die folgende Ausgabe zu erhalten?

["a", "d", "h", "b", "c", "e", "i", "f", "g"]

Die Reihenfolge der Elemente, die den gleichen "Schlüssel" haben, spielt keine Rolle. Ich kann auf die Verwendung von for Konstrukte, aber ich bin neugierig, ob es einen kürzeren Weg gibt. Irgendwelche Vorschläge?

827voto

Whatang Punkte 8642

Kürzester Code

[x for _, x in sorted(zip(Y, X))]

Exemple :

X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0,   1,   1,    0,   1,   2,   2,   0,   1]

Z = [x for _,x in sorted(zip(Y,X))]
print(Z)  # ["a", "d", "h", "b", "c", "e", "i", "f", "g"]

Allgemein gesprochen

[x for _, x in sorted(zip(Y, X), key=lambda pair: pair[0])]

Erklärt:

  1. zip die beiden list s.
  2. eine neue, sortierte list auf der Grundlage der zip mit sorted() .
  3. unter Verwendung eines Listenverständnisses Auszug die ersten Elemente eines jeden Paares aus der sortierten, gezippten list .

Für weitere Informationen über die Einstellung \use die key sowie der Parameter sorted Funktion im Allgemeinen, schauen Sie sich an ce .


146voto

Ned Batchelder Punkte 342778

Legen Sie die beiden Listen zusammen, sortieren Sie sie und nehmen Sie dann die gewünschten Teile heraus:

>>> yx = zip(Y, X)
>>> yx
[(0, 'a'), (1, 'b'), (1, 'c'), (0, 'd'), (1, 'e'), (2, 'f'), (2, 'g'), (0, 'h'), (1, 'i')]
>>> yx.sort()
>>> yx
[(0, 'a'), (0, 'd'), (0, 'h'), (1, 'b'), (1, 'c'), (1, 'e'), (1, 'i'), (2, 'f'), (2, 'g')]
>>> x_sorted = [x for y, x in yx]
>>> x_sorted
['a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g']

Kombinieren Sie diese, um zu erhalten:

[x for y, x in sorted(zip(Y, X))]

131voto

Tom Punkte 2439

Wenn es Ihnen nichts ausmacht, Numpy-Arrays zu verwenden (oder Sie bereits mit Numpy-Arrays arbeiten...), finden Sie hier eine weitere schöne Lösung:

people = ['Jim', 'Pam', 'Micheal', 'Dwight']
ages = [27, 25, 4, 9]

import numpy
people = numpy.array(people)
ages = numpy.array(ages)
inds = ages.argsort()
sortedPeople = people[inds]

Ich habe es hier gefunden: http://scienceoss.com/sort-one-list-by-another-list/

49voto

senderle Punkte 135243

Die naheliegendste Lösung ist für mich die Verwendung der key Schlüsselwort arg.

>>> X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
>>> Y = [ 0,   1,   1,    0,   1,   2,   2,   0,   1]
>>> keydict = dict(zip(X, Y))
>>> X.sort(key=keydict.get)
>>> X
['a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g']

Beachten Sie, dass Sie dies zu einem Einzeiler verkürzen können, wenn Sie dies möchten:

>>> X.sort(key=dict(zip(X, Y)).get)

Wie Wenmin Mu und Jack Peng dargelegt haben, wird dabei davon ausgegangen, dass die Werte in X sind alle unterschiedlich. Das lässt sich mit einer Indexliste leicht bewerkstelligen:

>>> Z = ["A", "A", "C", "C", "C", "F", "G", "H", "I"]
>>> Z_index = list(range(len(Z)))
>>> Z_index.sort(key=keydict.get)
>>> Z = [Z[i] for i in Z_index]
>>> Z
['A', 'C', 'H', 'A', 'C', 'C', 'I', 'F', 'G']

Da der Ansatz "dekorieren - sortieren - entdekorieren", wie er in Whatang ist ein wenig einfacher und funktioniert in allen Fällen, es ist wahrscheinlich besser die meiste Zeit. (Dies ist eine sehr alte Antwort!)

39voto

pylang Punkte 33775

more_itertools verfügt über ein Werkzeug zum parallelen Sortieren von Iterablen:

Gegeben

from more_itertools import sort_together

X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0,   1,   1,    0,   1,   2,   2,   0,   1]

Demo

sort_together([Y, X])[1]
# ('a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g')

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