J'ai une liste de chaînes comme celle-ci:
X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0, 1, 1, 0, 1, 2, 2, 0, 1]
Quel est le moyen le plus rapide de trier X en utilisant les valeurs de Y pour obtenir le résultat suivant?
["a", "d", "h", "b", "c", "e", "i", "f", "g"]
L'ordre des éléments ayant la même "clé" n'a pas d'importance. Je peux avoir recours à des constructions for
mais je suis curieux de savoir s'il existe un moyen plus court. Aucune suggestion?
Code le plus court
[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"]
En général
[x for _, x in sorted(Zip(Y,X), key=lambda pair: pair[0])]
Expliqué:
Zip
les deux list
s.list
triée en fonction de Zip
à l’aide de sorted()
.list
zippée et triée.Pour plus d'informations sur la manière de définir\utiliser le paramètre key
ainsi que la fonction sorted
en général, consultez this .
Compressez les deux listes ensemble, triez-les, puis prenez les parties souhaitées:
>>> 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']
Combinez ces éléments pour obtenir:
[x for y, x in sorted(Zip(Y, X))]
Aussi, si cela ne vous dérange pas d'utiliser des tableaux numpy (ou si vous avez déjà déjà affaire à des tableaux numpy ...), voici une autre solution intéressante:
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]
Je l'ai trouvé ici: http://scienceoss.com/sort-one-list-by-another-list/
La solution la plus évidente pour moi consiste à utiliser le mot clé key
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']
Notez que vous pouvez réduire cela à une ligne si vous vous souciez de:
>>> X.sort(key=dict(Zip(X, Y)).get)
J'aime avoir une liste d'index triés. De cette façon, je peux trier n'importe quelle liste dans le même ordre que la liste source. Une fois que vous avez une liste d'index triés, une compréhension simple de la liste fera l'affaire:
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"]
Notez que la liste d'index triée peut également être obtenue en utilisant numpy argsort ().
Une autre alternative, combinant plusieurs des réponses.
Zip(*sorted(Zip(Y,X)))[1]
Afin de travailler pour python3:
list(Zip(*sorted(Zip(B,A))))[1]
Zip, triez par la deuxième colonne, retournez la première colonne.
Zip(*sorted(Zip(X,Y), key=operator.itemgetter(1)))[0]
more_itertools
a un outil pour trier les iterables en parallèle:
from more_itertools import sort_together
sort_together([Y, X])[1]
# ('a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g')
En fait, je suis venu ici pour chercher une liste dans laquelle les valeurs correspondent.
list_a = ['foo', 'bar', 'baz']
list_b = ['baz', 'bar', 'foo']
sorted(list_b, key=lambda x: list_a.index(x))
# ['foo', 'bar', 'baz']
Un one-liner rapide.
list_a = [5,4,3,2,1]
list_b = [1,1.5,1.75,2,3,3.5,3.75,4,5]
Disons que vous voulez lister la liste correspondante b.
orderedList = sorted(list_a, key=lambda x: list_b.index(x))
Ceci est utile lorsque vous devez commander une liste plus petite à des valeurs plus grandes. En supposant que la liste la plus longue contienne toutes les valeurs de la liste la plus petite, cela peut être fait.
J'ai créé une fonction plus générale, qui trie plus de deux listes en fonction d'une autre, inspirée par la réponse 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
Vous pouvez créer un pandas Series
, en utilisant la liste primaire en tant que data
et l'autre liste en tant que index
, puis en triant simplement par l'index:
import pandas as pd
pd.Series(data=X,index=Y).sort_index().tolist()
sortie:
['a', 'd', 'h', 'b', 'c', 'e', 'i', 'f', 'g']
Whatangs répond si vous souhaitez obtenir les deux listes triées (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']
Rappelez-vous juste que Zx et Zy sont des n-uplets… Je me promène également s’il existe un meilleur moyen de le faire.
Attention: Si vous le lancez avec des listes vides, il se plante.
list1 = ['a','b','c','d','e','f','g','h','i']
list2 = [0,1,1,0,1,2,2,0,1]
output=[]
cur_loclist = []
Pour obtenir des valeurs uniques présentes dans list2
list_set = set(list2)
Pour trouver la localisation de l'index dans list2
list_str = ''.join(str(s) for s in list2)
La position de l'index dans list2
est suivie à l'aide de 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)