Listas Avançadas e Tuplas

Na última lição, aprendemos operações básicas de listas. Agora vamos explorar alguns conceitos mais "pytônicos" — a emoção das list comprehensions (uma linha fazendo o trabalho de cinco), e tuplas (a "lista imutável") e quando usá-las. Depois disso, seu código se parecerá cada vez mais com o de um verdadeiro programador Python.


1. Ordenação Avançada de Listas

Na Lição 10, aprendemos o básico de sort() e sorted(). Eles também aceitam um parâmetro key para especificar "qual regra usar para ordenar."

PYTHON
# Ordenar por comprimento da string
words = ["Python", "Java", "JavaScript", "C", "Go"]
sorted_by_len = sorted(words, key=len)
print(sorted_by_len)          # ['C', 'Go', 'Java', 'Python', 'JavaScript']

# Ordenar pelo último caractere
words = ["banana", "apple", "cherry", "date"]
sorted_by_last = sorted(words, key=lambda w: w[-1])
print(sorted_by_last)         # ['banana', 'date', 'apple', 'cherry']

# Ordenar por um elemento específico em uma tupla
scores = [("João Silva", 85), ("Maria Souza", 92), ("Pedro Santos", 78)]
sorted_scores = sorted(scores, key=lambda s: s[1], reverse=True)
print(sorted_scores)          # [('Maria Souza', 92), ('João Silva', 85), ('Pedro Santos', 78)]
💡 O parâmetro key é extremamente útil — você pode passar qualquer função que receba um argumento e retorne um valor. sorted() usará esse valor de retorno para ordenação. O lambda acima é uma função anônima, abordada em detalhes depois.

Exemplo: Gerando um Ranking (Dificuldade ⭐⭐)

PYTHON
# Ranking de jogo — ordenar por pontuação decrescente
players = [
    ("Jogador 1", 3500),
    ("Jogador 2", 5200),
    ("Jogador 3", 2800),
    ("Jogador 4", 4100),
]

# Ordenar por pontuação decrescente
ranked = sorted(players, key=lambda p: p[1], reverse=True)

print("=== Ranking ===")
for i, (name, score) in enumerate(ranked, 1):
    print(f"#{i}: {name} — {score} pontos")
▶ Experimente

Saída:

TEXT
=== Ranking ===
#1: Jogador 2 — 5200 pontos
#2: Jogador 4 — 4100 pontos
#3: Jogador 1 — 3500 pontos
#4: Jogador 3 — 2800 pontos

2. List Comprehensions

List comprehensions são um dos recursos mais amados do Python — gerar uma nova lista com uma única linha de código.

Sintaxe Básica

PYTHON
[expressão for variável in iterável]

Tradicional vs. Comprehension

PYTHON
# Gerar quadrados de 0~9 — forma tradicional
squares = []
for i in range(10):
    squares.append(i ** 2)
print(squares)                # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# Usando list comprehension — uma linha
squares = [i ** 2 for i in range(10)]
print(squares)                # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Comprehension com Condições

PYTHON
# Filtrar números pares
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = [n for n in numbers if n % 2 == 0]
print(evens)                  # [2, 4, 6, 8, 10]

# Converter strings para maiúsculas
words = ["hello", "world", "python"]
upper_words = [w.upper() for w in words]
print(upper_words)            # ['HELLO', 'WORLD', 'PYTHON']

# Filtrar palavras com comprimento >= 5
words = ["cat", "elephant", "dog", "giraffe", "ant"]
long_words = [w for w in words if len(w) >= 5]
print(long_words)             # ['elephant', 'giraffe']
💡 Comprehensions são concisas, mas não abuse. Se a lógica é complexa (ex.: laços aninhados ou múltiplas condições), um laço for regular é mais legível. Concisão não é igual a legibilidade.

Exemplo: Processamento de Dados (Dificuldade ⭐⭐)

PYTHON
# Dados brutos — podem conter valores vazios e espaços extras
raw_data = ["  João Silva  ", "", "  Maria Souza  ", "  Pedro Santos  ", "", "  Ana Oliveira  "]

# Limpeza em uma etapa com comprehension: strip + filtrar vazios
cleaned = [name.strip() for name in raw_data if name.strip()]
print(cleaned)                # ['João Silva', 'Maria Souza', 'Pedro Santos', 'Ana Oliveira']

# Processamento numérico
temps_c = [0, 10, 20, 30, 40]
temps_f = [c * 9 / 5 + 32 for c in temps_c]
print(temps_f)                # [32.0, 50.0, 68.0, 86.0, 104.0]
▶ Experimente

3. O que é uma Tupla

Tuplas são definidas com parênteses (). São similares a listas, mas com uma diferença chave — tuplas são imutáveis; uma vez criadas, não podem ser modificadas.

PYTHON
# Definir tuplas
point = (3, 5)
color = (255, 0, 0)
empty = ()
single = (42,)          # Nota: tuplas de um elemento devem ter vírgula!

print(point)            # (3, 5)
print(type(point))      # <class 'tuple'>

Tuplas são Imutáveis

PYTHON
point = (3, 5)
# point[0] = 10   ← Erro! Tuplas não podem ser modificadas
print(point[0])         # 3 — pode ler, não pode modificar

Por que Tuplas são Necessárias

A imutabilidade traz dois benefícios:

1. Podem ser usadas como chaves de dicionário (listas não podem, porque são mutáveis)

PYTHON
# Tuplas podem ser chaves de dicionário
locations = {
    (35.68, 139.76): "Tóquio",
    (31.23, 121.47): "Xangai",
}
print(locations[(35.68, 139.76)])   # Tóquio

# Listas não podem ser chaves
# d = {[1, 2]: "erro"}    ← Daria erro!

2. Representa dados que não devem ser modificados

PYTHON
# Coordenadas, cores, configurações — dados "imutáveis" são adequados para tuplas
RGB_RED = (255, 0, 0)        # Valor de vermelho não deve ser modificado
DEFAULT_CONFIG = ("localhost", 8080, "admin")
💡 Quando usar tuplas vs. listas? Uma regra simples: use listas se os dados precisam de modificação, use tuplas se não precisam. Funções que retornam múltiplos valores tipicamente usam tuplas.


4. Desempacotamento de Tuplas

Um dos recursos mais úteis de tuplas — desempacotamento, atribuindo elementos da tupla diretamente a múltiplas variáveis:

PYTHON
point = (3, 5)
x, y = point               # Desempacotamento
print(x)                   # 3
print(y)                   # 5

# Troca de variáveis — essencialmente desempacotamento de tupla
a, b = 10, 20
a, b = b, a                # Lado direito constrói tupla (20, 10), depois desempacota
print(a, b)                # 20 10

# Função retornando múltiplos valores
def get_min_max(numbers):
    return min(numbers), max(numbers)

result = get_min_max([3, 1, 4, 1, 5])
print(result)              # (1, 5)

low, high = get_min_max([3, 1, 4, 1, 5])
print(f"Min: {low}, Max: {high}")   # Min: 1, Max: 5

Usando _ para Ignorar Valores Não Desejados

PYTHON
data = ("João Silva", 25, "São Paulo", "Engenheiro")
name, _, city, _ = data     # Use _ para significar "não me importo com isso"
print(f"{name} mora em {city}")  # João Silva mora em São Paulo

Exemplo: Cálculo de Coordenadas (Dificuldade ⭐⭐)

PYTHON
# Define dois pontos
p1 = (1, 2)
p2 = (4, 6)

# Desempacota para cálculo de distância
x1, y1 = p1
x2, y2 = p2

distance = ((x2 - x1)  2 + (y2 - y1)  2) ** 0.5
print(f"Distância: {distance:.2f}")     # 5.00

# Usando enumerate para iteração indexada
fruits = ["maçã", "banana", "laranja"]
for i, fruit in enumerate(fruits, 1):
    print(f"{i}. {fruit}")
▶ Experimente

Saída:

TEXT
Distância: 5.00
1. maçã
2. banana
3. laranja

5. Guia de Seleção: Lista vs. Tupla

Característica Lista Tupla
Mutável ✅ Pode adicionar/remover/alterar ❌ Imutável
Velocidade Ligeiramente mais lenta Ligeiramente mais rápida
Memória Ligeiramente maior Ligeiramente menor
Pode ser chave de dict
Caso de uso Dados frequentemente modificados Dados fixos e imutáveis
Usos típicos Carrinho de compras, lista de tarefas, dados dinâmicos Coordenadas, cores, valores de retorno de função
💡 Um hábito prático: Se você não tem certeza de qual usar, comece com uma lista. Listas são mais flexíveis na maioria dos cenários. Quando você descobrir que alguns dados realmente não devem ser modificados, mude para uma tupla.


Casos de Uso Comuns


❓ Perguntas Frequentes

P: Qual é mais rápido — list comprehensions ou laços for regulares? R: List comprehensions são tipicamente mais rápidas porque executam o laço no nível C em vez do nível Python. No entanto, a diferença é perceptível apenas com grandes quantidades de dados (dezenas de milhares de itens). Na codificação diária, priorize a legibilidade primeiro. P: Por que uma tupla de um elemento precisa de vírgula? Qual a diferença entre (42) e (42,)? R: Os parênteses em (42) são interpretados como agrupamento matemático, não uma tupla — type((42)) retorna <class 'int'>. (42,) é uma tupla. Portanto, tuplas de um elemento devem incluir uma vírgula: (42,). P: Como o parâmetro key em sorted() funciona? Dê um exemplo prático. R: O cenário mais comum é ordenar por um atributo específico. Por exemplo, ordenar por comprimento de string: sorted(words, key=len). Ordenar pelo segundo elemento de tuplas em uma lista: sorted(data, key=lambda x: x[1]). Ordenar por valores de dicionário: sorted(dict.items(), key=lambda x: x[1]). O segredo é entender que key aceita uma função que mapeia cada elemento a uma chave de ordenação.


📖 Resumo


📝 Atividades

  1. Iniciante (Dificuldade ⭐): Use uma list comprehension para gerar os quadrados de todos os números entre 1 e 20 que são divisíveis por 3. Dica: [expressão for n in range(...) if condição]

  2. Intermediário (Dificuldade ⭐⭐): Dada uma lista de nomes names = [" alice ", "BOB", " charlie", " david "], use uma list comprehension em uma etapa: remova espaços + capitalize a primeira letra e minúsculas no resto. Dica: strip() para espaços, title() ou capitalize() para maiúsculas.

  3. Avançado (Dificuldade ⭐⭐⭐): Escreva uma função analyze_numbers(*args) que aceita qualquer número de argumentos numéricos e retorna uma tupla (max, min, média, contagem_acima_da_média). Dica: Use *args para argumentos de comprimento variável; use uma list comprehension para contar valores acima da média.

100%