Pular para o conteúdo principal

Aula 11: Tuplas e Conjuntos


Objetivos de Aprendizagem

Ao final desta aula, você será capaz de:

  1. Criar e acessar tuplas, compreendendo sua imutabilidade
  2. Identificar situações em que tuplas são preferíveis a listas
  3. Criar conjuntos (set) e utilizá-los para eliminar duplicatas
  4. Aplicar operações de conjunto: união, interseção e diferença
  5. Comparar listas, tuplas e conjuntos, escolhendo a estrutura adequada

Conteúdo Teórico

1. Tuplas

O que é uma tupla?

Uma tupla é uma sequência ordenada de elementos, assim como a lista — mas com uma diferença fundamental: ela é imutável. Uma vez criada, seus elementos não podem ser alterados, adicionados ou removidos.

# Lista — mutável
frutas_lista = ["maçã", "banana", "laranja"]
frutas_lista[0] = "uva" # OK

# Tupla — imutável
frutas_tupla = ("maçã", "banana", "laranja")
frutas_tupla[0] = "uva" # TypeError: 'tuple' object does not support item assignment
Conceito Fundamental

Imutabilidade significa que o objeto não pode ser modificado após sua criação. Isso garante que os dados permanecem íntegros e protegidos contra alterações acidentais.

Criando tuplas

Tuplas são delimitadas por parênteses ():

coordenada = (10.5, -23.4) # par de coordenadas geográficas
rgb = (255, 128, 0) # cor laranja em RGB
vazia = () # tupla vazia
um_elemento = (42,) # tupla com um elemento — a vírgula é obrigatória!

# Sem parênteses também funciona (empacotamento de tupla)
ponto = 3, 7
print(type(ponto)) # <class 'tuple'>
Dica

(42) não é uma tupla — é apenas o número 42 entre parênteses. Para criar uma tupla de um único elemento, a vírgula final é obrigatória: (42,).

Acessando elementos

Tuplas usam a mesma indexação e fatiamento das listas:

cores = ("vermelho", "verde", "azul")

print(cores[0]) # vermelho
print(cores[-1]) # azul
print(cores[1:]) # ('verde', 'azul')
print(len(cores)) # 3

Desempacotamento de tupla

Uma das características mais úteis das tuplas é o desempacotamento: atribuir os elementos da tupla a variáveis separadas em uma única linha.

ponto = (3, 7)
x, y = ponto
print(f"x={x}, y={y}") # x=3, y=7

# Útil ao iterar com enumerate ou .items()
aluno = {"nome": "João", "nota": 9.5}
for chave, valor in aluno.items():
print(f"{chave}{valor}")

Quando usar tupla em vez de lista?

Use tupla quando:

  • Os dados são fixos por natureza — coordenadas GPS, data de nascimento, configurações constantes
  • Você quer proteger os dados contra modificação acidental
  • Os dados serão usados como chave de dicionário (listas não podem ser chaves; tuplas podem)
  • A semântica indica um registro com posições fixas: (latitude, longitude), (dia, mês, ano)

Use lista quando você precisa adicionar, remover ou modificar elementos após a criação.

CaracterísticaListaTupla
MutabilidadeMutávelImutável
Sintaxe[a, b, c](a, b, c)
Pode ser chave de dictNãoSim
Uso típicoColeções que mudamRegistros fixos

2. Conjuntos (Sets)

O que é um conjunto?

Um conjunto (set) é uma coleção não ordenada de elementos únicos (sem duplicatas). Ele é inspirado no conceito matemático de conjunto.

# Criando um conjunto
linguagens = {"Python", "Java", "C++", "Python", "Java"}
print(linguagens)
# {'Python', 'Java', 'C++'} — duplicatas removidas automaticamente
Conceito Fundamental

Dois princípios definem os conjuntos:

  1. Unicidade: cada elemento aparece no máximo uma vez
  2. Sem ordem garantida: a posição dos elementos não é preservada — não há índice

Criando conjuntos

numeros = {1, 2, 3, 4, 5}
vazio = set() # conjunto vazio — NÃO use {}, pois {} cria dicionário vazio!

# A partir de uma lista (remove duplicatas)
notas_brutas = [8.0, 7.5, 8.0, 9.0, 7.5, 6.0]
notas_unicas = set(notas_brutas)
print(notas_unicas) # {8.0, 7.5, 9.0, 6.0}

Adicionando e removendo elementos

frutas = {"maçã", "banana"}

frutas.add("laranja") # adiciona um elemento
frutas.remove("banana") # remove — KeyError se não existir
frutas.discard("uva") # remove sem erro se não existir
print(len(frutas)) # 2

# Verificar pertencimento — muito eficiente em conjuntos
print("maçã" in frutas) # True

3. Operações de Conjunto

As operações matemáticas de conjuntos estão disponíveis em Python tanto por métodos quanto por operadores:

A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}

União — | ou .union()

Todos os elementos de A e de B (sem repetição):

print(A | B) # {1, 2, 3, 4, 5, 6, 7, 8}
print(A.union(B)) # mesmo resultado

Interseção — & ou .intersection()

Apenas os elementos que estão em A e em B:

print(A & B) # {4, 5}
print(A.intersection(B)) # {4, 5}

Diferença — - ou .difference()

Elementos que estão em A mas não estão em B:

print(A - B) # {1, 2, 3}
print(A.difference(B)) # {1, 2, 3}

Diferença simétrica — ^ ou .symmetric_difference()

Elementos que estão em A ou em B, mas não nos dois:

print(A ^ B) # {1, 2, 3, 6, 7, 8}
print(A.symmetric_difference(B)) # {1, 2, 3, 6, 7, 8}

Subconjunto e superconjunto

C = {1, 2}
print(C.issubset(A)) # True — C ⊆ A
print(A.issuperset(C)) # True — A ⊇ C

4. Exemplo Prático: Removendo Duplicatas e Comparando Listas

# Alunos que entregaram TP1 e TP2
entregaram_tp1 = ["Ana", "Bruno", "Carlos", "Diana", "Ana"]
entregaram_tp2 = ["Bruno", "Diana", "Eduardo", "Carlos"]

set_tp1 = set(entregaram_tp1)
set_tp2 = set(entregaram_tp2)

print("Entregaram ambos os TPs:", set_tp1 & set_tp2)
# {'Bruno', 'Carlos', 'Diana'}

print("Entregaram apenas o TP1:", set_tp1 - set_tp2)
# {'Ana'}

print("Entregaram apenas o TP2:", set_tp2 - set_tp1)
# {'Eduardo'}

print("Entregaram pelo menos um:", set_tp1 | set_tp2)
# {'Ana', 'Bruno', 'Carlos', 'Diana', 'Eduardo'}

5. Comparativo Geral das Estruturas

CaracterísticaListaTuplaConjuntoDicionário
Ordenada?SimSimNãoSim (Python 3.7+)
Mutável?SimNãoSimSim
Duplicatas?SimSimNãoChaves únicas
Acesso por índice?SimSimNãoPor chave
Sintaxe[](){}{k: v}

Exercícios / Checkpoints

Checkpoint 1: Tuplas básicas

Crie uma tupla representando uma data (dia, mes, ano). Desempacote-a em três variáveis e imprima no formato "Data: DD/MM/AAAA". Tente modificar um dos elementos e descreva o erro que ocorre.

Checkpoint 2: Tuplas como chaves de dicionário

Crie um dicionário que mapeie coordenadas (latitude, longitude) para nomes de cidades:

cidades = {
(-23.55, -46.63): "São Paulo",
(-22.91, -43.17): "Rio de Janeiro",
(-19.92, -43.94): "Belo Horizonte"
}

Acesse e imprima o nome da cidade de São Paulo usando sua coordenada como chave.

Checkpoint 3: Eliminando duplicatas

Dado o cadastro de inscrições abaixo (com repetições por erro de sistema), use conjuntos para encontrar os inscritos únicos e contar quantos são:

inscricoes = ["Ana", "Bruno", "Carlos", "Ana", "Diana", "Bruno", "Eduardo", "Carlos", "Ana"]

Checkpoint 4: Operações de conjunto

Duas turmas fizeram o mesmo curso em semestres diferentes:

turma_2025_1 = {"Alice", "Bob", "Carol", "David", "Eva"}
turma_2025_2 = {"Bob", "Frank", "Grace", "Alice", "Henry"}

Usando operações de conjunto, encontre:

  1. Alunos que estão nas duas turmas (reprovaram e repetiram)
  2. Alunos exclusivos de cada turma
  3. Total de alunos distintos entre as duas turmas

Checkpoint 5: Escolha de estrutura

Para cada situação, justifique qual estrutura (list, tuple, set ou dict) é mais apropriada:

  1. Os três colocados em um pódio de corrida (1º, 2º, 3º lugar com nome do atleta)
  2. Os CPFs de todos os usuários cadastrados num sistema (sem repetição, sem ordem)
  3. O histórico de páginas visitadas em um navegador (na ordem em que foram abertas)
  4. As configurações de conexão com banco de dados (host, porta, usuário, senha)

Situações Problema

As duas situações abaixo são para implementação em aula. Elas exigem a combinação de vários conceitos da aula — não há uma única solução certa. Incentive os alunos a experimentar, errar e discutir abordagens diferentes.


Situação Problema 1: Controle de Presença e Aprovação por Frequência

Contexto: Uma disciplina realiza chamada em cada aula. Cada chamada é registrada como um conjunto de alunos presentes naquele dia. A frequência mínima para aprovação é de 75% das aulas realizadas. Os dados de cada aluno também incluem matrícula e nome, armazenados como tuplas.

Código inicial:

alunos = [
("2024001", "Ana"),
("2024002", "Bruno"),
("2024003", "Carlos"),
("2024004", "Diana"),
("2024005", "Eduardo"),
("2024006", "Flávia"),
]

chamadas = [
{"Ana", "Bruno", "Carlos", "Diana"},
{"Ana", "Carlos", "Eduardo", "Flávia"},
{"Ana", "Bruno", "Diana", "Flávia"},
{"Bruno", "Carlos", "Diana"},
{"Ana", "Carlos", "Eduardo"},
{"Ana", "Bruno", "Diana", "Flávia"},
{"Ana", "Carlos", "Diana", "Eduardo"},
{"Bruno", "Diana", "Flávia"},
]

Tarefas:

  1. Determine quantas aulas cada aluno frequentou.
  2. Calcule o percentual de frequência e classifique cada aluno como aprovado por frequência (>= 75%) ou reprovado por falta.
  3. Liste os alunos que nunca compareceram a nenhuma aula.
  4. Exiba um relatório ordenado por frequência decrescente, com matrícula, nome, presenças e percentual.
Dica

Use união de conjuntos para descobrir quem já apareceu em pelo menos uma chamada e sorted(..., key=..., reverse=True) para ordenar o relatório.

Ver solução
TOTAL_AULAS = len(chamadas)
MINIMO = 0.75

presencas = {}
for matricula, nome in alunos:
contagem = 0
for chamada in chamadas:
if nome in chamada:
contagem += 1
presencas[matricula] = contagem

resultado = []
for matricula, nome in alunos:
qtd = presencas[matricula]
perc = qtd / TOTAL_AULAS
if perc >= MINIMO:
situacao = "Aprovado por frequência"
else:
situacao = "Reprovado por falta"
resultado.append((matricula, nome, qtd, perc, situacao))

todos_presentes = set()
for chamada in chamadas:
todos_presentes |= chamada

ausentes = []
for mat, nome in alunos:
if nome not in todos_presentes:
ausentes.append((mat, nome))

# ordenacao manual por percentual (maior para menor)
resultado_ordenado = list(resultado)
for i in range(len(resultado_ordenado)):
indice_maior = i
for j in range(i + 1, len(resultado_ordenado)):
if resultado_ordenado[j][3] > resultado_ordenado[indice_maior][3]:
indice_maior = j
temp = resultado_ordenado[i]
resultado_ordenado[i] = resultado_ordenado[indice_maior]
resultado_ordenado[indice_maior] = temp

for mat, nome, qtd, perc, sit in resultado_ordenado:
print(mat, nome, f"{qtd}/{TOTAL_AULAS}", f"{perc*100:.1f}%", sit)
print("Ausentes sempre:", ausentes)

Situação Problema 2: Análise de Preferências em Pesquisa de Disciplinas

Contexto: Uma pesquisa pediu a cada aluno que indicasse quais disciplinas optativas deseja cursar no próximo semestre. As respostas vieram como listas e podem conter repetições por erro de formulário.

Código inicial:

respostas_brutas = [
(("2024001", "Ana"), ["IA", "redes", "IA", " Banco de Dados", "Compiladores"]),
(("2024002", "Bruno"), ["Redes", "banco de dados", "IA", "Redes"]),
(("2024003", "Carlos"), ["compiladores", "IA", "Redes", "Compiladores"]),
(("2024004", "Diana"), ["banco de dados", " IA", "redes", "Compiladores"]),
(("2024005", "Eduardo"), ["IA", "banco de dados", "IA"]),
]

Tarefas:

  1. Normalize as respostas removendo duplicatas por aluno e padronizando com .strip().lower().
  2. Calcule quantos alunos escolheram cada disciplina e ordene por popularidade (maior para menor).
  3. Encontre as disciplinas escolhidas por todos os alunos (interseção global).
  4. Para cada par de alunos, liste as disciplinas em comum (apenas pares com interseção não vazia).
Dica

Converta cada lista de respostas em set para simplificar deduplicação e operações de interseção.

Ver solução
preferencias = {}
for aluno_tupla, lista in respostas_brutas:
disciplinas = set()
for d in lista:
disciplinas.add(d.strip().lower())
preferencias[aluno_tupla] = disciplinas

popularidade = {}
for discs in preferencias.values():
for d in discs:
if d not in popularidade:
popularidade[d] = 0
popularidade[d] += 1

# ordenacao manual da popularidade (maior para menor)
popularidade_lista = list(popularidade.items())
for i in range(len(popularidade_lista)):
indice_maior = i
for j in range(i + 1, len(popularidade_lista)):
if popularidade_lista[j][1] > popularidade_lista[indice_maior][1]:
indice_maior = j
temp = popularidade_lista[i]
popularidade_lista[i] = popularidade_lista[indice_maior]
popularidade_lista[indice_maior] = temp

print(popularidade_lista)

sets_lista = list(preferencias.values())
comuns = sets_lista[0]
for s in sets_lista[1:]:
comuns &= s
print("Comuns a todos:", comuns)

alunos_lista = list(preferencias.keys())
for i in range(len(alunos_lista)):
for j in range(i + 1, len(alunos_lista)):
em_comum = preferencias[alunos_lista[i]] & preferencias[alunos_lista[j]]
if em_comum:
print(alunos_lista[i][1], "&", alunos_lista[j][1], sorted(em_comum))

Resumo da Aula

Nesta aula, você aprendeu:

  • Tuplas são sequências ordenadas e imutáveis — use quando os dados não devem mudar
  • O desempacotamento de tuplas permite atribuir múltiplos valores em uma linha
  • Conjuntos armazenam elementos únicos sem ordem — ideal para eliminar duplicatas
  • Operações de conjunto (|, &, -, ^) permitem comparar coleções eficientemente
  • A escolha entre lista, tupla, conjunto e dicionário depende de: mutabilidade, ordem, unicidade e forma de acesso

Próxima aula: Combinando Estruturas de Dados — listas de dicionários e outras composições para modelar dados complexos


Referências

Leitura Essencial

Aprofundamento (Opcional)

  • Python Software Foundation. frozenset. Disponível em: docs.python.org/3/library/stdtypes.html#frozenset
    • Variante imutável do conjunto — pode ser usada como chave de dicionário.
  • Lutz, M. Aprendendo Python. 5ª ed. São Paulo: O'Reilly Brasil, 2013.
    • Capítulo sobre tipos de sequências aprofunda as distinções entre listas, tuplas e conjuntos com exemplos avançados.