Leyenda
Tengo una lista de cadenas como esta:
X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0, 1, 1, 0, 1, 2, 2, 0, 1 ]
¿Cuál es la forma más corta de ordenar X usando valores de Y para obtener el siguiente resultado?
["a", "d", "h", "b", "c", "e", "i", "f", "g"]
El orden de los elementos que tienen la misma “clave” no importa. Puedo recurrir al uso de for
construye pero tengo curiosidad si hay una forma más corta. ¿Alguna sugerencia?
Quéang
Código más corto
[x for _, x in sorted(zip(Y, X))]
Ejemplo:
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"]
Generalmente hablando
[x for _, x in sorted(zip(Y, X), key=lambda pair: pair[0])]
Explicado:
zip
los doslist
s.- crear un nuevo, ordenado
list
basado en elzip
usandosorted()
. - usando una lista de comprensión extracto los primeros elementos de cada par de los ordenados, comprimidos
list
.
Para obtener más información sobre cómo configurar\usar el key
parámetro, así como el sorted
función en general, eche un vistazo a este.
-
Esto es correcto, pero agregaré la nota de que si está tratando de ordenar varias matrices por la misma matriz, esto no necesariamente funcionará como se esperaba, ya que la clave que se usa para ordenar es (y, x) , no solo y. En su lugar, debe utilizar [x for (y,x) in sorted(zip(Y,X), key=lambda pair: pair[0])]
– gms7777
17/01/2014 a las 20:33
-
¡buena solución! Pero debería serlo: la lista se ordena con respecto al primer elemento de los pares, y la comprensión extrae el ‘segundo’ elemento de los pares.
– Programa de control maestro
06/10/2017 a las 14:31
-
Esta solución es pobre cuando se trata de almacenamiento. Se prefiere una clasificación en el lugar siempre que sea posible.
– Demonio del odio
30 de junio de 2019 a las 16:27
-
@Hatefiend interesante, ¿podría señalar una referencia sobre cómo lograr eso?
– RichieV
3 de septiembre de 2020 a las 3:18
-
@RichieV Recomiendo usar Quicksort o una implementación de clasificación de combinación en el lugar. Una vez que tenga eso, defina su propia función de comparación que compare valores en función de los índices de la lista
Y
. El resultado final debe ser una lista.Y
estar intacto y listaX
siendo cambiado a la solución esperada sin tener que crear una lista temporal.– Demonio del odio
9 de septiembre de 2020 a las 5:26
Comprima las dos listas, ordénelas y luego tome las partes que desee:
>>> 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']
Combina estos para obtener:
[x for y, x in sorted(zip(Y, X))]
-
esto esta bien si
X
es una lista destr
pero tenga cuidado si existe la posibilidad de que<
no está definido para algunos pares de artículos enX
por ejemplo, si algunos de ellos fueranNone
– John LaRooy
23 de agosto de 2017 a las 5:05
-
Cuando tratamos de usar ordenar sobre un objeto zip,
AttributeError: 'zip' object has no attribute 'sort'
es lo que estoy recibiendo a partir de ahora.– Ash Upadhyay
23 de enero de 2018 a las 12:57
-
Está utilizando Python 3. En Python 2, zip produjo una lista. Ahora produce un objeto iterable.
sorted(zip(...))
debería seguir funcionando, o:them = list(zip(...)); them.sort()
–Ned Batchelder
23 de enero de 2018 a las 16:38
Además, si no le importa usar matrices numpy (o, de hecho, ya está tratando con matrices numpy…), aquí hay otra buena solución:
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]
Lo encontré aquí:
http://scienceoss.com/ordenar-una-lista-por-otra-lista/
-
Para arreglos/vectores más grandes, ¡esta solución con numpy es beneficiosa!
– Programa de control maestro
06/10/2017 a las 14:53
-
Si ya son matrices numpy, entonces es simplemente
sortedArray1= array1[array2.argsort()]
. Y esto también facilita la clasificación de múltiples listas por una columna particular de una matriz 2D: por ejemplosortedArray1= array1[array2[:,2].argsort()]
para ordenar array1 (que puede tener múltiples columnas) por los valores en la tercera columna de array2.– Aarón Bramson
12 de junio de 2018 a las 8:50
enviarle
La solución más obvia para mí es usar el key
palabra clave argumento
>>> 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']
Tenga en cuenta que puede acortar esto a una sola línea si desea:
>>> X.sort(key=dict(zip(X, Y)).get)
Como han señalado Wenmin Mu y Jack Peng, esto supone que los valores en X
son todos distintos. Eso se maneja fácilmente con una lista de índice:
>>> 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']
Dado que el enfoque decorar-clasificar-desdecorar descrito por Whatang es un poco más simple y funciona en todos los casos, probablemente sea mejor la mayor parte del tiempo. (¡Esta es una respuesta muy antigua!)
pilang
more_itertools
tiene una herramienta para ordenar iterables en paralelo:
Dado
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]
Manifestación
sort_together([Y, X])[1]
# ('a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g')
-
Me gusta esto porque puedo hacer múltiples listas con un índice
sort_together([Index,X,Y,Z])
– Túnel
23 oct 2021 a las 14:02
-
Oh, ignora, también puedo hacer sorted(zip(Index,X,Y,Z)).
– Túnel
23 oct 2021 a las 14:19
nackjicholson
De hecho, vine aquí buscando ordenar una lista por una lista donde los valores coincidieran.
list_a = ['foo', 'bar', 'baz']
list_b = ['baz', 'bar', 'foo']
sorted(list_b, key=lambda x: list_a.index(x))
# ['foo', 'bar', 'baz']
-
Me gusta esto porque puedo hacer múltiples listas con un índice
sort_together([Index,X,Y,Z])
– Túnel
23 oct 2021 a las 14:02
-
Oh, ignora, también puedo hacer sorted(zip(Index,X,Y,Z)).
– Túnel
23 oct 2021 a las 14:19
Otra alternativa, combinar varias de las respuestas.
zip(*sorted(zip(Y,X)))[1]
Para trabajar para python3:
list(zip(*sorted(zip(B,A))))[1]
-
original: stackoverflow.com/a/6620187
– djvg
23 de enero a las 11:36
La respuesta de riza podría ser útil al graficar datos, ya que zip(*sorted(zip(X, Y), key=lambda pair: pair[0])) devuelve tanto el X como el Y ordenados con valores de X.
– jil
15 mayo 2014 a las 12:37
Caso más general (ordenar la lista Y por cualquier clave en lugar del orden predeterminado)
– usuario202729
1 oct 2020 a las 8:37
Aunque puede que no sea obvio, esto es exactamente equivalente a clasificación Y, y reorganizando X de la misma manera que se ordenó Y. Estas dos preguntas las tenía guardadas desde hace bastante tiempo – y me angustiaba por ellas, porque algo no me parecía del todo bien – hasta hoy que me di cuenta de la duplicación (después de trabajar la otra para que quedara más clara y mejorar el título).
– Karl Knechtel
2 de marzo a las 5:41