¿Cómo ordenar una lista / tupla de listas / tuplas por elemento en un índice dado?

659

Tengo algunos datos en una lista de listas o en una lista de tuplas, como esta:

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

Y quiero ordenar por el segundo elemento en el subconjunto. Es decir, ordenar por 2,5,8 de dónde 2es (1,2,3), 5es de (4,5,6). ¿Cuál es la forma común de hacer esto? ¿Debo almacenar tuplas o listas en mi lista?

Stan
fuente
51
Con respecto a "¿Debo almacenar tuplas o listas en mi lista?", Una regla general es hacer que las cosas sean lo más inmutables posible. Si no necesita modificar las sublistas en su lugar, conviértalas en tuplas.
Matthew Flaschen

Respuestas:

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

o:

data.sort(key=lambda tup: tup[1])  # sorts in place
Stephen
fuente
10
¿Alguna idea de cómo ordenarlo de mayor a menor?
billwild
63
@billwild: ayuda (ordenada). reverso = verdadero.
Stephen
34
@Stephen usando itemgetter es más rápido y sencillo: key=itemgetter(1)y al comienzo del archivo:from operator import itemgetter
Joschua
3
@Cemre como para el segundo ejemplo, sortaquí hay un método de Listobjeto de Python, que recibe una función lambda como keyparámetro. Puedes nombrarlo como tup, o t, o lo que quieras y seguirá funcionando. tupaquí especifica el índice de la tupla de la lista, por 1lo que significa que la clasificación se realizará por los segundos valores de las tuplas de la lista original ( 2, 5, 8).
Neurotransmisor
1
Estaba un poco escéptico ante la afirmación infundada de que "usar itemgetter es más rápido y más simple". Si bien considero subjetivamente que el lambdaenfoque intuitivo es más simple que la itemgetterclase itemgetter no intuitiva , de hecho parece ser más rápido . Tengo curiosidad de por qué es esto. Mi sospecha es que lambdaincurre en el costo oculto de capturar todas las variables locales en un contexto de cierre, mientras que una itemgetterinstancia no lo hace. tl; dr: siempre use itemgetter, porque la velocidad gana.
Cecil Curry
236
from operator import itemgetter
data.sort(key=itemgetter(1))
manova
fuente
37
Esta debería ser la respuesta aceptada. Vea también los tiempos publicados de Charlie , demostrando que la clase clasifica 126% más rápido en promedio que la función equivalente . itemgetterlambda
Cecil Curry
99
También puede ordenar por múltiples índices jerárquicamente, por ejemplodata.sort(key=itemgetter(3,1))
Michael Ohlrogge
58

Solo quiero agregar a la respuesta de Stephen si desea ordenar la matriz de mayor a menor, otra forma que no sea en los comentarios anteriores es agregar esto a la línea:

reverse = True

y el resultado será el siguiente:

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

Para ordenar por múltiples criterios, es decir, por ejemplo, por el segundo y el tercer elemento en una tupla, dejemos

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

y así definir una lambda que devuelve una tupla que describe la prioridad, por ejemplo

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

La respuesta de Stephen es la que usaría. Para completar, aquí está el patrón DSU (decorar-ordenar-decorar) con listas de comprensión:

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

O, más brevemente:

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

Como se señaló en Python Sorting HowTo , esto ha sido innecesario desde Python 2.4, cuando las funciones clave estuvieron disponibles.

tcarobruce
fuente
2
Entonces, ¿esta respuesta es útil para Python 2.3-? ¿Hay algún uso válido en las versiones de Python más actuales sobre las que podría elaborar un poco? Si no, no te molestes ... solo pasaba, vi esto y el viejo noggin comenzó a revolverse un poquito. De todos modos, saludos y gracias por esta caminata de regreso a los primeros días de Python.
Mechanical_meat
19

Para ordenar una lista de tuplas (<word>, <count>), counten orden descendente y worden orden alfabético:

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

Yo uso este método:

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

y me da el resultado:

[('butter', 2),
('a', 1),
('betty', 1),
('bit', 1),
('bitter', 1),
('bought', 1),
('but', 1),
('of', 1),
('the', 1),
('was', 1)]
l mingzhi
fuente
1
¿Qué pasa si tup [1] es una cadena?
Eric
12

Sin lambda:

def sec_elem(s):
    return s[1]

sorted(data, key=sec_elem)
Mesco
fuente
9

itemgetter()es algo más rápido que lambda tup: tup[1], pero el aumento es relativamente modesto (alrededor del 10 al 25 por ciento).

(Sesión de 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
fuente
Consulte la solución de ordenación itemgetter para variar los argumentos inversos para varias columnas aquí, luego debe organizar su clasificación en varios pasos seguidos: stackoverflow.com/questions/14466068/…
Lorenz
6

¡La respuesta de @Stephen es al grano! Aquí hay un ejemplo para una mejor visualización,

¡Grita a los fanáticos 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')]

keyes una función que se llamará para transformar los elementos de la colección para comparación ... como compareTométodo en Java.

El parámetro pasado a la clave debe ser algo invocable. Aquí, el uso de lambdacrea una función anónima (que es invocable).
La sintaxis de lambda es la palabra lambda seguida de un nombre iterable y luego un solo bloque de código.

Debajo del ejemplo, estamos ordenando una lista de tuplas que contiene la información sobre el tiempo de cierto evento y el nombre del actor.

Estamos ordenando esta lista por hora de ocurrencia del evento, que es el elemento 0 de una tupla.

Nota: s.sort([cmp[, key[, reverse]]]) ordena los elementos de s en su lugar

Rishi
fuente
-5

Ordenar una tupla es bastante simple:

tuple(sorted(t))
Jayr
fuente