Como classificar uma lista / tupla de listas / tuplas pelo elemento em um determinado índice?

658

Eu tenho alguns dados em uma lista de listas ou em uma 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)]

E eu quero classificar pelo segundo elemento no subconjunto. O significado, ordenando por 2,5,8 de onde 2é (1,2,3), 5é de (4,5,6). Qual é a maneira comum de fazer isso? Devo armazenar tuplas ou listas na minha lista?

Stan
fonte
51
Com relação a "Devo armazenar tuplas ou listas na minha lista?", Uma regra geral é tornar as coisas o mais imutáveis ​​possível. Se você não precisar modificar as sublistas, faça-as tuplas.
Matthew Flaschen

Respostas:

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

ou:

data.sort(key=lambda tup: tup[1])  # sorts in place
Stephen
fonte
10
Alguma idéia de como classificá-lo maior para menor?
billwild
63
@ billwild: help (classificado). reverse = True.
Stephen
34
@Stephen usando itemgetter é mais rápido e mais simples: key=itemgetter(1)e no início do arquivo:from operator import itemgetter
Joschua
3
@Cemre, como no segundo exemplo, sortaqui está um método de Listobjeto do Python, que recebe uma função lambda como keyparâmetro. Você pode nomeá-lo como tup, ou t, ou o que quiser e ainda funcionará. tupaqui especifica o índice da tupla da lista, o que 1significa que a classificação será realizada pelos segundos valores das tuplas da lista original ( 2, 5, 8).
Neurotransmitter
1
Fiquei levemente cético em relação à alegação infundada de que "o uso do itemgetter é mais rápido e mais simples". Embora eu subjetivamente considere a lambdaabordagem intuitiva mais simples que a itemgetterclasse itemgetter não intuitiva , na verdade parece ser mais rápida . Estou curioso para saber por que isso acontece. Minha suspeita grosseira é que a lambdaincorre no custo oculto de capturar todas as variáveis ​​locais em um contexto de fechamento, enquanto uma itemgetterinstância não. tl; dr: Sempre use itemgetter, porque a velocidade vence.
Cecil Curry
236
from operator import itemgetter
data.sort(key=itemgetter(1))
manova
fonte
37
Essa deve ser a resposta aceita. Veja também os horários publicados por Charlie , demonstrando que a classe é classificada 126% mais rápido, em média, do que a função equivalente . itemgetterlambda
Cecil Curry
9
Você também pode classificar por vários índices hierarquicamente, por exemplodata.sort(key=itemgetter(3,1))
Michael Ohlrogge
57

Eu só quero adicionar a resposta de Stephen se você quiser classificar o array de alto a baixo, outra maneira que não seja nos comentários acima é apenas adicionar isso à linha:

reverse = True

e o resultado será o seguinte:

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

Para classificar por vários critérios, ou seja, pelo segundo e terceiro elementos de uma tupla, deixe

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

e, assim, defina uma lambda que retorne uma tupla que descreva a prioridade, por exemplo

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

A resposta de Stephen é a que eu usaria. Para completar, eis o padrão DSU (decorate-sort-undecorate) com compreensões de lista:

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

Ou, mais sucintamente:

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

Conforme observado no Python Sorting HowTo , isso é desnecessário desde o Python 2.4, quando as principais funções se tornaram disponíveis.

tcarobruce
fonte
2
Portanto, esta resposta é útil para o Python 2.3-? Existem usos válidos nas versões mais atuais do Python em torno das quais você pode elaborar um pouco? Caso contrário, não se preocupe ... estava passando, viu isso e o velho canguru começou a agitar um pouquinho. De qualquer forma, aplausos e agradecimentos por essa caminhada de volta aos dias anteriores do Python.
Mechanical_meat
19

Para classificar uma lista de tuplas (<word>, <count>), countem ordem decrescente e wordem ordem alfabética:

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

Eu uso este método:

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

e isso me dá o resultado:

[('butter', 2),
('a', 1),
('betty', 1),
('bit', 1),
('bitter', 1),
('bought', 1),
('but', 1),
('of', 1),
('the', 1),
('was', 1)]
l mingzhi
fonte
1
e se tup [1] for uma string?
eric
12

Sem lambda:

def sec_elem(s):
    return s[1]

sorted(data, key=sec_elem)
Mesco
fonte
9

itemgetter()é um pouco mais rápido que lambda tup: tup[1], mas o aumento é relativamente modesto (cerca de 10 a 25%).

(Sessão 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
fonte
Consulte a solução de classificação itemgetter para obter vários argumentos reversos para várias colunas aqui. Você precisará organizar sua classificação em várias etapas seguidas: stackoverflow.com/questions/14466068/…
Lorenz
6

A resposta de @Stephen é direta! Aqui está um exemplo para uma melhor visualização,

Grite para os fãs do 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')]

keyé uma função que será chamada para transformar os itens da coleção para comparação .. como o compareTométodo em Java.

O parâmetro passado para a chave deve ser algo que pode ser chamado. Aqui, o uso de lambdacria uma função anônima (que é uma chamada).
A sintaxe do lambda é a palavra lambda seguida por um nome iterável e depois por um único bloco de código.

Abaixo do exemplo, estamos classificando uma lista de tuplas que contém as informações após o tempo de determinado evento e nome do ator.

Estamos classificando essa lista por hora da ocorrência do evento - que é o 0º elemento de uma tupla.

Nota - s.sort([cmp[, key[, reverse]]]) classifica os itens de s no lugar

Rishi
fonte
-5

Classificar uma tupla é bastante simples:

tuple(sorted(t))
Jayr
fonte