Lista de clasificación según los valores correspondientes de una lista paralela [duplicate]

7 minutos de lectura

Avatar de usuario de Legend
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?

  • 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

Avatar de usuario de Whatang
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:

  1. zip los dos lists.
  2. crear un nuevo, ordenado list basado en el zip usando sorted().
  3. 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 lista X 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 de strpero tenga cuidado si existe la posibilidad de que < no está definido para algunos pares de artículos en Xpor ejemplo, si algunos de ellos fueran None

    – 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 ejemplo sortedArray1= 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

avatar de usuario de senderle
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!)

avatar de usuario de pylang
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

avatar de usuario de nackjicholson
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

¿Ha sido útil esta solución?