python - ejemplos - Ordenar lista basada en valores de otra lista?
django (14)
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 clasificar X utilizando 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
constructos, pero tengo curiosidad si hay un camino más corto. ¿Alguna sugerencia?
Además, si no te importa usar matrices numpy (o de hecho ya estás 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/sort-one-list-by-another-list/
Aquí está la respuesta de Whatangs si desea obtener ambas listas ordenadas (python3).
X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0, 1, 1, 0, 1, 2, 2, 0, 1]
Zx, Zy = zip(*[(x, y) for x, y in sorted(zip(Y, X))])
print(list(Zx)) # [0, 0, 0, 1, 1, 1, 1, 2, 2]
print(list(Zy)) # [''a'', ''d'', ''h'', ''b'', ''c'', ''e'', ''i'', ''f'', ''g'']
Solo recuerda que Zx y Zy son tuplas. También estoy vagando si hay una mejor manera de hacerlo.
Advertencia: si lo ejecutas con listas vacías se bloquea.
Comprima las dos listas juntas, clasifíquelas, 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))]
En realidad, vine aquí para ordenar una lista por una lista donde coincidían los valores.
list_a = [''foo'', ''bar'', ''baz'']
list_b = [''baz'', ''bar'', ''foo'']
sorted(list_b, key=lambda x: list_a.index(x))
# [''foo'', ''bar'', ''baz'']
He creado una función más general, que ordena más de dos listas basadas en otra, inspirada en la respuesta de @ Whatang.
def parallel_sort(*lists):
"""
Sorts the given lists, based on the first one.
:param lists: lists to be sorted
:return: a tuple containing the sorted lists
"""
# Create the initially empty lists to later store the sorted items
sorted_lists = tuple([] for _ in range(len(lists)))
# Unpack the lists, sort them, zip them and iterate over them
for t in sorted(zip(*lists)):
# list items are now sorted based on the first list
for i, item in enumerate(t): # for each item...
sorted_lists[i].append(item) # ...store it in the appropriate list
return sorted_lists
La solución más obvia para mí es usar la palabra key
clave 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'']
Tenga en cuenta que puede acortar esto a una sola línea si le interesa:
>>> X.sort(key=dict(zip(X, Y)).get)
Me gusta tener una lista de índices ordenados. De esa manera, puedo ordenar cualquier lista en el mismo orden que la lista de fuentes. Una vez que tenga una lista de índices ordenados, una simple lista de comprensión hará el truco:
X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0, 1, 1, 0, 1, 2, 2, 0, 1]
sorted_y_idx_list = sorted(range(len(Y)),key=lambda x:Y[x])
Xs = [X[i] for i in sorted_y_idx_list ]
print( "Xs:", Xs )
# prints: Xs: ["a", "d", "h", "b", "c", "e", "i", "f", "g"]
Tenga en cuenta que la lista de índice ordenada también se puede obtener utilizando numpy argsort ().
Otra alternativa, combinando varias de las respuestas.
zip(*sorted(zip(Y,X)))[1]
Para trabajar en python3:
list(zip(*sorted(zip(B,A))))[1]
Puedes crear una pandas Series
, usando la lista principal como data
y la otra lista como index
, y luego ordenarlas por el índice:
import pandas as pd
pd.Series(data=X,index=Y).sort_index().tolist()
salida:
[''a'', ''d'', ''h'', ''b'', ''c'', ''e'', ''i'', ''f'', ''g'']
Un rápido de una sola línea.
list_a = [5,4,3,2,1]
list_b = [1,1.5,1.75,2,3,3.5,3.75,4,5]
Digamos que quieres una lista de coincidencias b.
orderedList = sorted(list_a, key=lambda x: list_b.index(x))
Esto es útil cuando se necesita ordenar una lista más pequeña a valores más grandes. Suponiendo que la lista más grande contenga todos los valores en la lista más pequeña, se puede hacer.
zip, ordenar por la segunda columna, devolver la primera columna.
zip(*sorted(zip(X,Y), key=operator.itemgetter(1)))[0]
more_itertools
tiene una herramienta para ordenar iterables en paralelo:
from more_itertools import sort_together
sort_together([Y, X])[1]
# (''a'', ''d'', ''h'', ''b'', ''c'', ''e'', ''i'', ''f'', ''g'')
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
las doslist
s. - cree una nueva
list
ordenada basada en elzip
usandosorted()
. - utilizando una lista de comprensión, extraiga los primeros elementos de cada par de la
list
ordenada y comprimida.
Para obtener más información sobre cómo configurar / usar el parámetro key
, así como la función sorted
en general, eche un vistazo a this .
list1 = [''a'',''b'',''c'',''d'',''e'',''f'',''g'',''h'',''i'']
list2 = [0,1,1,0,1,2,2,0,1]
output=[]
cur_loclist = []
Para obtener valores únicos presentes en la list2
list_set = set(list2)
Para encontrar la ubicación del índice en la list2
list_str = ''''.join(str(s) for s in list2)
La ubicación del índice en la list2
se rastrea mediante cur_loclist
[0, 3, 7, 1, 2, 4, 8, 5, 6]
for i in list_set:
cur_loc = list_str.find(str(i))
while cur_loc >= 0:
cur_loclist.append(cur_loc)
cur_loc = list_str.find(str(i),cur_loc+1)
print(cur_loclist)
for i in range(0,len(cur_loclist)):
output.append(list1[cur_loclist[i]])
print(output)