Python Ordenando Listas
A professora quer a chamada em ordem alfabética. A Ana quer ver as notas da maior para a menor. O caixa quer os preços do mais barato ao mais caro. Pôr uma lista em ordem (em inglês, sort, "ordenar") é uma das coisas mais úteis que o Python faz, e ele faz em uma linha. Mas há detalhes que pegam todo mundo: a diferença entre sort() e sorted(), as maiúsculas que vêm antes das minúsculas e os nomes com acento que vão parar no fim da lista.
- A ordenar a própria lista com
sort(), e a criar uma lista nova ordenada comsorted(). - A ordem decrescente com
reverse=True, e a inverter uma lista comreverse(),reversed()e[::-1]. - Como o Python compara textos, e por que
"Zé"vem antes de"ana"e o"Álvaro"vai para o fim. - A escolher o critério com
key:key=str.lower,key=len,key=int. - Os erros reais:
lista = lista.sort()(a lista viraNone) e a lista com números e textos misturados.
A ideia: arrumar as fichas, ou tirar uma cópia arrumada
A professora tem as fichas dos alunos numa caixa, fora de ordem. Ela pode fazer duas coisas:
- Arrumar as fichas na própria caixa. Depois disso, a ordem antiga se perdeu. É o
lista.sort(). - Deixar a caixa como está e escrever uma folha nova, com os nomes em ordem. A caixa original continua igual. É o
sorted(lista).
Os dois põem em ordem do mesmo jeito; a diferença é o que acontece com a lista original.
1. sort(): ordena a própria lista
notas = [7.0, 9.5, 6.5, 10.0, 8.0] notas.sort() print(notas) notas.sort(reverse=True) print(notas)
$ python3 sort.py [6.5, 7.0, 8.0, 9.5, 10.0] [10.0, 9.5, 8.0, 7.0, 6.5]
- notas.sort()
- O método
sort("ordenar") põe os itens da listanotasem ordem crescente, do menor para o maior. Ele muda a própria lista e, como oappend, devolveNone: a linha não tem=. - reverse=True
- "Ao contrário = verdadeiro": a ordem fica decrescente, do maior para o menor. É um argumento nomeado: você escreve o nome (
reverse), o=e o valor (aula Valores Padrão e Argumentos Nomeados).
Missão: o programa mostra as notas da menor para a maior. Faça-o mostrar da maior para a menor, usando reverse=True.
notas = [7.0, 9.5, 6.5, 10.0, 8.0] notas.sort() print(notas)
notas = [7.0, 9.5, 6.5, 10.0, 8.0] notas.sort(reverse=True) print(notas)
2. sorted(): cria uma lista nova, ordenada
turma = ["Davi", "Ana", "Carla", "Bruno"]
em_ordem = sorted(turma)
print("Ordenada:", em_ordem)
print("Original:", turma)
print("Ao contrário:", sorted(turma, reverse=True))
$ python3 sorted.py Ordenada: ['Ana', 'Bruno', 'Carla', 'Davi'] Original: ['Davi', 'Ana', 'Carla', 'Bruno'] Ao contrário: ['Davi', 'Carla', 'Bruno', 'Ana']
- sorted(turma)
- Uma função (não um método: vem antes, com a lista entre parênteses). Ela devolve uma lista nova, em ordem, e não toca na original.
- em_ordem = …
- Aqui o
=está certo: osorteddevolve a lista nova, e você a guarda. - Original
- A
turmacontinua na ordem em que foi escrita. - sorted(turma, reverse=True)
- O
reverse=Truefunciona igual nosorted.
O sorted também ordena coisas que não são listas (um texto, uma tupla, as chaves de um dicionário) e sempre devolve uma lista. O sort() só existe nas listas.
lista.sort() | sorted(lista) | |
|---|---|---|
| O que é | Método da lista | Função |
| A lista original | Muda (a ordem antiga se perde) | Fica como estava |
| Devolve | None | Uma lista nova, ordenada |
| Como escrever | notas.sort(), sozinho na linha | em_ordem = sorted(notas) ou dentro de um print, for… |
| Use quando | Você não precisa mais da ordem antiga | Você quer as duas ordens, ou só vai mostrar em ordem |
3. Como o Python compara textos
Com números, "em ordem" é óbvio. Com textos, o Python compara letra por letra, da esquerda para a direita, como no dicionário. Só que ele não usa o alfabeto que você aprendeu na escola: cada caractere tem um número (o código Unicode), e a ordem é a desses números. A função ord() mostra o número de um caractere:
>>> ord("A")
65
>>> ord("Z")
90
>>> ord("a")
97
>>> ord("Á")
193
>>> "Zé" < "ana"
True
>>> "Álvaro" < "Bruno"
False
Todas as maiúsculas sem acento (65 a 90) vêm antes de todas as minúsculas (97 a 122), e as letras com acento vêm depois de todas elas (o Á é o 193). Por isso "Zé" é "menor" que "ana", e "Álvaro" é "maior" que "Bruno". Duas consequências que você precisa conhecer:
Maiúsculas antes das minúsculas
nomes = ["bruno", "Davi", "ana", "Carla"] print(sorted(nomes)) print(sorted(nomes, key=str.lower))
$ python3 maiusculas.py ['Carla', 'Davi', 'ana', 'bruno'] ['ana', 'bruno', 'Carla', 'Davi']
Na primeira linha, os nomes com maiúscula vieram antes, e os com minúscula depois: não é a ordem que uma pessoa espera. A segunda linha resolve com o key, que você vai ver na seção 4: key=str.lower quer dizer "compare como se tudo estivesse em minúsculas". Repare que os nomes continuam escritos como estavam; só a comparação ignora as maiúsculas.
O Álvaro vai para o fim
nomes = ["Bruno", "Álvaro", "Ana", "Carla", "Érica", "Eduardo"] print(sorted(nomes))
$ python3 acentos.py ['Ana', 'Bruno', 'Carla', 'Eduardo', 'Álvaro', 'Érica']
O Álvaro, que deveria ser o primeiro da chamada, foi para depois do Eduardo, junto com a Érica. Não é um erro do Python: é a regra dos números dos caracteres. O Á (193) vem depois de qualquer letra sem acento.
locale
O Python tem um jeito de comparar textos pelas regras de um idioma: o módulo locale (aula Módulos e import) e a função locale.strxfrm, usada como key. No terminal da Ana, com o português do Brasil instalado:
import locale locale.setlocale(locale.LC_COLLATE, "pt_BR.UTF-8") nomes = ["Bruno", "Álvaro", "Ana", "Carla", "Érica", "Eduardo"] print(sorted(nomes, key=locale.strxfrm))
$ python3 acentos_locale.py ['Álvaro', 'Ana', 'Bruno', 'Carla', 'Eduardo', 'Érica']
Agora o Álvaro abre a chamada. Mas esse resultado depende dos idiomas instalados no computador: se o pt_BR.UTF-8 não estiver instalado, o setlocale para o programa com locale.Error: unsupported locale setting ("configuração de idioma não suportada"). E no editor do guia, que roda no navegador, o mesmo programa roda sem erro, mas sai na ordem do sorted comum, com o Álvaro no fim. Por isso, neste guia, fica só como nota.
4. Escolhendo o critério: key
O key ("chave") diz ao Python: "antes de comparar, passe cada item por esta função, e compare o resultado". Os itens em si não mudam; só a régua usada para comparar.
- key=str.lower
- Compara pela versão em minúsculas de cada texto:
"Davi"é comparado como"davi". - key=len
- Compara pelo tamanho de cada item.
- key=int
- Compara pelo número que o texto representa.
Repare que depois do key= vai o nome da função, sem parênteses: key=len, e não key=len(). Você não está chamando a função; está dizendo ao sort qual função ele deve chamar, item por item.
Pelo tamanho
compras = ["café", "arroz", "pão", "feijão", "sal"] print(sorted(compras, key=len))
$ python3 tamanho.py ['pão', 'sal', 'café', 'arroz', 'feijão']
Do item mais curto (3 letras) para o mais longo (6). O pão e o sal têm o mesmo tamanho, e ficaram na ordem em que já estavam na lista: quando dois itens "empatam", o Python mantém a ordem original entre eles.
Números guardados como texto
As senhas da fila do banco chegaram como texto. Ordenadas assim, o resultado é estranho:
senhas = ["10", "9", "2", "100"] print(sorted(senhas)) print(sorted(senhas, key=int))
$ python3 texto_numero.py ['10', '100', '2', '9'] ['2', '9', '10', '100']
Como textos, eles são comparados caractere por caractere: "10" começa com "1", que vem antes de "2", então "10" e "100" ficam antes do "2". Com key=int, cada texto é comparado como o número que representa, e a ordem fica certa. (Os itens continuam sendo textos: repare nas aspas.)
Listas dentro de listas
Quando os itens são listas, o Python compara o primeiro item de cada uma; se empatar, o segundo, e assim por diante:
>>> turma = [["Davi", 7.0], ["Ana", 9.5], ["Carla", 8.0]] >>> sorted(turma) [['Ana', 9.5], ['Carla', 8.0], ['Davi', 7.0]]
Ficou em ordem de nome. Para ordenar pela nota (o segundo item), o key precisa de uma função que pegue o item 1 de cada par. Você vai aprender a escrever essas funções nas aulas Funções e lambda.
Missão: alguns nomes foram digitados em minúsculas e a chamada saiu fora de ordem. Use o key para ordenar sem ligar para maiúsculas.
chamada = ["carla", "Davi", "ana", "Bruno"] print(sorted(chamada))
chamada = ["carla", "Davi", "ana", "Bruno"] print(sorted(chamada, key=str.lower))
5. Invertendo a ordem (sem ordenar)
Às vezes você não quer ordenar: quer só a lista de trás para frente, como ela está. Há três jeitos:
fila = ["Ana", "Bruno", "Carla"]
fila.reverse()
print(fila)
fila = ["Ana", "Bruno", "Carla"]
print(fila[::-1])
print(list(reversed(fila)))
for nome in reversed(fila):
print(nome)
print(fila)
$ python3 inverter.py ['Carla', 'Bruno', 'Ana'] ['Carla', 'Bruno', 'Ana'] ['Carla', 'Bruno', 'Ana'] Carla Bruno Ana ['Ana', 'Bruno', 'Carla']
- fila.reverse()
- Método: inverte a própria lista e devolve
None, como osort(). - fila[::-1]
- Uma fatia com passo -1 (aula Acessando Itens): uma lista nova, invertida.
- reversed(fila)
- Uma função que entrega os itens de trás para frente, sem criar uma lista. É perfeita no
for. Para ter uma lista, ponha numlist(). - print(fila)
- A última linha prova:
[::-1]ereversednão mudaram a fila.
Se você mostrar o reversed(fila) direto, não aparece uma lista, e sim um objeto que entrega os itens quando alguém pede (o número no fim é um endereço da memória, e muda a cada execução):
>>> fila = ["Ana", "Bruno", "Carla"] >>> reversed(fila) <list_reverseiterator object at 0x7f78566ef070>
reverse() não é "ordem decrescente"
notas.reverse() só vira a lista de cabeça para baixo: [7, 10, 8] vira [8, 10, 7], que não está em ordem nenhuma. Para a ordem decrescente, é notas.sort(reverse=True).
Formas diferentes de ordenar: qual usar
| Você quer | Escreva | A lista original |
|---|---|---|
| Ordenar a lista e esquecer a ordem antiga | lista.sort() | Muda |
| Uma cópia ordenada | nova = sorted(lista) | Fica igual |
| Do maior para o menor | lista.sort(reverse=True) ou sorted(lista, reverse=True) | Muda / fica igual |
| Textos sem ligar para maiúsculas | sorted(lista, key=str.lower) | Fica igual |
| Pelo tamanho | sorted(lista, key=len) | Fica igual |
| Números que estão em texto | sorted(lista, key=int) | Fica igual |
| Só inverter a ordem atual | lista.reverse(), lista[::-1] ou reversed(lista) | Muda / igual / igual |
| Mostrar em ordem, uma vez | for x in sorted(lista): | Fica igual |
Quando dá errado
lista = lista.sort(): a lista vira None
O mesmo erro do append, com outro método:
compras = ["leite", "arroz", "feijão", "café"] compras = compras.sort() print(compras) print(compras[0])
$ python3 sort_none.py
None
Traceback (most recent call last):
File "/home/ana/sort_none.py", line 4, in <module>
print(compras[0])
~~~~~~~^^^
TypeError: 'NoneType' object is not subscriptable
Linha por linha:
- Linha 2: o
sort()ordenou a lista e devolveuNone; o=guardou esseNoneemcompras. A lista ordenada ficou sem nome e se perdeu. - Linha 3: o
printmostrouNone. - Linha 4:
TypeError: 'NoneType' object is not subscriptable, "o objetoNoneTypenão aceita colchetes". Subscriptable é "que aceita índice". ONonenão tem itens, entãocompras[0]não faz sentido.
Você pode ver o None direto:
>>> fila = ["Ana", "Bruno", "Carla"] >>> print(fila.sort()) None
Como consertar: ou compras.sort() sozinho na linha, ou compras = sorted(compras). Nunca os dois misturados. O reverse() tem o mesmo comportamento.
coisas = [3, "2", 1] coisas.sort() print(coisas)
$ python3 mistura.py
Traceback (most recent call last):
File "/home/ana/mistura.py", line 2, in <module>
coisas.sort()
~~~~~~~~~~~^^
TypeError: '<' not supported between instances of 'str' and 'int'
"O < não funciona entre um str e um int". Para ordenar, o Python precisa perguntar "este é menor que aquele?" (com o <), e ele não sabe dizer se o texto "2" é menor que o número 3. Quase sempre, isso acontece quando alguns números vieram do input() como texto. Como consertar: converta tudo para o mesmo tipo antes (int(), aula Conversão de Tipos), ou ordene com key=int se todos forem números escritos como texto.
Três surpresas que não dão mensagem nenhuma, só um resultado esquisito:
- Minúsculas depois das maiúsculas:
['Carla', 'Davi', 'ana', 'bruno']. Usekey=str.lower. - Acentos no fim: o Álvaro depois do Eduardo. É a ordem dos códigos dos caracteres; veja a nota sobre
localena seção 3. - Números em texto:
['10', '100', '2', '9']. Usekey=int, ou guarde os números como números.
Referência rápida
| Escrita | O que faz | Devolve |
|---|---|---|
lista.sort() | Ordena a própria lista, do menor para o maior | None |
lista.sort(reverse=True) | …do maior para o menor | None |
lista.sort(key=função) | …comparando função(item) | None |
sorted(lista) | Cria uma lista nova ordenada (aceita reverse e key) | A lista nova |
lista.reverse() | Inverte a própria lista | None |
reversed(lista) | Entrega os itens de trás para frente (para o for ou o list()) | Um iterador |
lista[::-1] | Cria uma lista nova invertida | A lista nova |
key=str.lower / key=len / key=int | Ignorar maiúsculas / pelo tamanho / pelo número do texto | — |
| Sintoma | Causa provável |
|---|---|
A lista virou None | lista = lista.sort() ou lista = lista.reverse() |
TypeError: 'NoneType' object is not subscriptable | A variável recebeu None antes (quase sempre pelo motivo acima) |
TypeError: '<' not supported between instances of 'str' and 'int' | Lista com números e textos misturados |
| Minúsculas depois das maiúsculas | A ordem é a dos códigos: use key=str.lower |
| Nomes com acento no fim | A ordem é a dos códigos (Á = 193) |
'10' antes de '2' | Números guardados como texto: key=int |
| A lista "ao contrário" não está em ordem | Usou reverse() em vez de sort(reverse=True) |
Exercícios
1. Do maior para o menor
Complete para ordenar os preços do mais caro para o mais barato:
2. Uma cópia em ordem
Complete com a função que devolve uma lista nova, ordenada, sem mudar turma:
3. Sem ligar para maiúsculas
Complete o critério:
4. Depois de a = [3, 1, 2] e b = sorted(a), quanto vale a?
5. O que mostra print(sorted(["bia", "Ana", "Caio"]))?
6. Qual linha deixa notas igual a None?
Missão final: a lista em ordem
Missão: a Ana quer a lista de compras em ordem alfabética e o primeiro item, mas o programa mostra None e quebra. Conserte a linha do sort.
compras = ["leite", "arroz", "feijão", "café"]
compras = compras.sort()
print(compras)
print(f"Primeiro: {compras[0]}")
compras = ["leite", "arroz", "feijão", "café"]
compras.sort()
print(compras)
print(f"Primeiro: {compras[0]}")
Resumo
lista.sort()ordena a própria lista e devolveNone;sorted(lista)devolve uma lista nova e não mexe na original.reverse=Truedá a ordem decrescente, nos dois.key=funçãoescolhe o critério:str.lower(ignorar maiúsculas),len(tamanho),int(números em texto). Sem parênteses depois do nome.- Textos são comparados pelos códigos dos caracteres: maiúsculas antes das minúsculas, e letras com acento depois de todas (o Álvaro vai para o fim).
reverse(),reversed()e[::-1]só invertem a ordem atual; não ordenam.- Nunca
lista = lista.sort(). E não dá para ordenar números misturados com textos.