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?

Stan
la source
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
Stephen
la source
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))
manova
la source
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)
sifoo
la source
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)]
orme
la source
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.

tcarobruce
la source
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)]
l mingzhi
la source
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)
Mesco
la source
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
Walter
la source
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

Rishi
la source
-5

Le tri d'un tuple est assez simple:

tuple(sorted(t))
Jayr
la source