Comment trier une liste / tuple de listes / tuples par l'élément à un index donné?


659

J'ai des données dans une liste de listes ou une liste de tuples, comme ceci:

data = [[1,2,3], [4,5,6], [7,8,9]]
data = [(1,2,3), (4,5,6), (7,8,9)]

Et je veux trier par le 2ème élément du sous-ensemble. Signification, tri par 2,5,8 d'où 2vient (1,2,3), 5vient de (4,5,6). Quelle est la manière la plus courante de procéder? Dois-je stocker des tuples ou des listes dans ma liste?


51
En ce qui concerne "Dois-je stocker des tuples ou des listes dans ma liste?", Une règle d'or consiste à rendre les choses aussi immuables que possible. Si vous n'avez pas besoin de modifier les sous-listes en place, faites-en des tuples.
Matthew Flaschen

Réponses:


1117
sorted_by_second = sorted(data, key=lambda tup: tup[1])

ou:

data.sort(key=lambda tup: tup[1])  # sorts in place

10
Une idée de comment le trier du plus grand au plus petit?
billwild

63
@billwild: aide (trié). inverse = Vrai.
Stephen

34
@Stephen utilisant itemgetter est plus rapide et plus simple: key=itemgetter(1)et au début du fichier:from operator import itemgetter
Joschua

3
@Cemre comme pour le deuxième exemple, sortvoici une méthode d' Listobjet de Python, qui reçoit une fonction lambda comme keyparamètre. Vous pouvez le nommer comme tup, ou t, ou ce que vous voulez et cela fonctionnera toujours. tupspécifie ici l'index du tuple de la liste, ce 1qui signifie que le tri sera effectué par les secondes valeurs des tuples de la liste d'origine ( 2, 5, 8).
Neurotransmetteur

1
J'étais légèrement sceptique quant à l'affirmation non fondée selon laquelle "utiliser itemgetter est plus rapide et plus simple". Bien que je considère subjectivement l' lambdaapproche intuitive comme plus simple que la itemgetterclasse non intuitive , itemgetter elle semble en effet être plus rapide . Je suis curieux de savoir pourquoi c'est. Ma grossière suspicion est que a lambdaentraîne le coût caché de la capture de toutes les variables locales dans un contexte de fermeture, contrairement à une itemgetterinstance. tl; dr: Toujours utiliser itemgetter, car la vitesse gagne.
Cecil Curry

236
from operator import itemgetter
data.sort(key=itemgetter(1))

37
Ce devrait être la réponse acceptée. Voir aussi les horaires affichés par Charlie , démontrant la classe pour trier 126% plus rapidement en moyenne que la fonction équivalente . itemgetterlambda
Cecil Curry

9
Vous pouvez également trier hiérarchiquement plusieurs indices, par exempledata.sort(key=itemgetter(3,1))
Michael Ohlrogge

58

Je veux juste ajouter à la réponse de Stephen si vous voulez trier le tableau de haut en bas, une autre manière que dans les commentaires ci-dessus consiste simplement à ajouter ceci à la ligne:

reverse = True

et le résultat sera le suivant:

data.sort(key=lambda tup: tup[1], reverse=True)

48

Pour trier selon plusieurs critères, à savoir par exemple par les deuxième et troisième éléments d'un tuple, laissez

data = [(1,2,3),(1,2,1),(1,1,4)]

et ainsi définir un lambda qui renvoie un tuple qui décrit la priorité, par exemple

sorted(data, key=lambda tup: (tup[1],tup[2]) )
[(1, 1, 4), (1, 2, 1), (1, 2, 3)]

28

La réponse de Stephen est celle que j'utiliserais. Pour être complet, voici le modèle DSU (décorer-trier-décorer) avec des listes de compréhension:

decorated = [(tup[1], tup) for tup in data]
decorated.sort()
undecorated = [tup for second, tup in decorated]

Ou, plus laconiquement:

[b for a,b in sorted((tup[1], tup) for tup in data)]

Comme indiqué dans le HowTo de tri Python , cela n'a pas été nécessaire depuis Python 2.4, lorsque les fonctions clés sont devenues disponibles.


2
Cette réponse est donc utile pour Python 2.3-? Existe-t-il des utilisations valides dans les versions plus récentes de Python autour desquelles vous pourriez élaborer un peu? Sinon, pas la peine ... passait juste par là, a vu ça et la vieille cabane s'est mise à baratiner un tout petit peu. Quoi qu'il en soit, bravo et merci pour cette promenade dans les premiers jours de Python.
mechanical_meat

19

Afin de trier une liste de tuples (<word>, <count>), countpar ordre décroissant et wordpar ordre alphabétique:

data = [
('betty', 1),
('bought', 1),
('a', 1),
('bit', 1),
('of', 1),
('butter', 2),
('but', 1),
('the', 1),
('was', 1),
('bitter', 1)]

J'utilise cette méthode:

sorted(data, key=lambda tup:(-tup[1], tup[0]))

et ça me donne le résultat:

[('butter', 2),
('a', 1),
('betty', 1),
('bit', 1),
('bitter', 1),
('bought', 1),
('but', 1),
('of', 1),
('the', 1),
('was', 1)]

1
que faire si tup [1] est une chaîne?
Eric

12

Sans lambda:

def sec_elem(s):
    return s[1]

sorted(data, key=sec_elem)

9

itemgetter()est un peu plus rapide que lambda tup: tup[1], mais l'augmentation est relativement modeste (environ 10 à 25 pour cent).

(Session IPython)

>>> from operator import itemgetter
>>> from numpy.random import randint
>>> values = randint(0, 9, 30000).reshape((10000,3))
>>> tpls = [tuple(values[i,:]) for i in range(len(values))]

>>> tpls[:5]    # display sample from list
[(1, 0, 0), 
 (8, 5, 5), 
 (5, 4, 0), 
 (5, 7, 7), 
 (4, 2, 1)]

>>> sorted(tpls[:5], key=itemgetter(1))    # example sort
[(1, 0, 0), 
 (4, 2, 1), 
 (5, 4, 0), 
 (8, 5, 5), 
 (5, 7, 7)]

>>> %timeit sorted(tpls, key=itemgetter(1))
100 loops, best of 3: 4.89 ms per loop

>>> %timeit sorted(tpls, key=lambda tup: tup[1])
100 loops, best of 3: 6.39 ms per loop

>>> %timeit sorted(tpls, key=(itemgetter(1,0)))
100 loops, best of 3: 16.1 ms per loop

>>> %timeit sorted(tpls, key=lambda tup: (tup[1], tup[0]))
100 loops, best of 3: 17.1 ms per loop

Veuillez consulter la solution de tri itemgetter pour faire varier les arguments inverses pour plusieurs colonnes ici, vous devez ensuite organiser votre tri en plusieurs étapes consécutives: stackoverflow.com/questions/14466068/…
Lorenz

6

La réponse de @Stephen est au point! Voici un exemple pour une meilleure visualisation,

Bravo aux fans de Ready Player One! =)

>>> gunters = [('2044-04-05', 'parzival'), ('2044-04-07', 'aech'), ('2044-04-06', 'art3mis')]
>>> gunters.sort(key=lambda tup: tup[0])
>>> print gunters
[('2044-04-05', 'parzival'), ('2044-04-06', 'art3mis'), ('2044-04-07', 'aech')]

keyest une fonction qui sera appelée pour transformer les éléments de la collection à des fins de comparaison .. comme la compareTométhode en Java.

Le paramètre passé à key doit être quelque chose qui peut être appelé. Ici, l'utilisation de lambdacrée une fonction anonyme (qui est appelable).
La syntaxe de lambda est le mot lambda suivi d'un nom itérable puis d'un seul bloc de code.

Dans l'exemple ci-dessous, nous trions une liste de tuple contenant les informations sur l'heure de certains événements et noms d'acteurs.

Nous trions cette liste par heure d'occurrence de l'événement - qui est le 0ème élément d'un tuple.

Remarque - s.sort([cmp[, key[, reverse]]]) trie les éléments de s en place


-5

Le tri d'un tuple est assez simple:

tuple(sorted(t))
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.