Conteúdos da cadeira

Dicionários e conjuntos

Associações chave-valor, métodos de dicionários, conjuntos e operações entre conjuntos.

Markdown

Perguntar sobre esta página

ChatGPTClaudePerplexityGeminiCopiar e abrir

Envia o link e pede à IA para ler a página. No Gemini, cola a pergunta copiada.

Ver pergunta para copiar
Nesta página

Listas e tuplos encontram elementos pela posição. Muitos problemas pedem outra pergunta: dado um nome, qual é o valor associado? A nota do aluno 202400123, a contagem da palavra casa, o código do produto e o seu preço. Para estas associações existe o dicionário; para coleções sem repetições nem ordem existe o conjunto.

Dicionários: chaves e valores

Um dicionário guarda pares chave-valor entre chavetas. As chaves têm de ser de tipo imutável (strings, números e tuplos servem; listas não servem). Os valores podem ser de qualquer tipo.

notas = {'Ana': 17, 'Bruno': 12}
notas['Carla'] = 15
print(notas['Ana'])
print(len(notas))

Isto escreve 17 e 3. Atribuir a uma chave nova acrescenta o par; atribuir a uma chave existente substitui o valor. Os dicionários são mutáveis e não têm ordem por posição: para encontrar um valor, dás a chave, e o acesso é muito rápido mesmo em dicionários grandes, graças a uma técnica chamada dispersão (hashing).

Os métodos essenciais são:

MétodoO que faz
get(chave, omissao)Devolve o valor, ou omissao se a chave não existir
keys()As chaves
values()Os valores
items()Os pares (chave, valor)
pop(chave)Remove o par e devolve o valor
copy()Cópia superficial do dicionário

Pedir uma chave inexistente com parênteses retos levanta KeyError e o programa morre se não tratar o erro. O get evita isso: notas.get('Diana', 0) devolve 0 quando a Diana não está no dicionário. Usa get com valor por omissão sempre que a ausência for um caso normal, como inicializar contagens.

Percorrer um dicionário percorre as suas chaves. Para teres chaves e valores ao mesmo tempo, usa items:

notas = {'Ana': 17, 'Bruno': 12, 'Carla': 15}
for nome, nota in notas.items():
    print(nome, nota)

Isto escreve as três linhas, numa ordem que não deves assumir como fixa. Repara ainda que o in aplicado a um dicionário testa apenas as chaves: 'Ana' in notas é True, mas 17 in notas é False.

Exemplo com dicionários: contar palavras

Contar ocorrências é o exercício canónico dos dicionários. O padrão: para cada palavra, lê a contagem atual com get (que devolve 0 na primeira vez) e guarda a contagem mais um.

def contar(texto):
    """Devolve um dicionário com a contagem de cada palavra."""
    contagem = {}
    for palavra in texto.split():
        contagem[palavra] = contagem.get(palavra, 0) + 1
    return contagem

print(contar('o rato roeu a rolha do rato'))

Isto escreve {'o': 1, 'rato': 2, 'roeu': 1, 'a': 1, 'rolha': 1, 'do': 1}. Segue a palavra 'rato': na primeira ocorrência, get devolve 0 e guarda 1; na segunda, get devolve 1 e guarda 2. Sem o get, a primeira ocorrência tentaria ler uma chave que ainda não existe e levantaria KeyError.

Conjuntos: elementos únicos sem ordem

Um conjunto (set) é uma coleção mutável de elementos únicos e sem ordem. Escreve-se com chavetas, mas sem pares: {'a', 'b'} é um conjunto, {'a': 1} é um dicionário. O conjunto vazio escreve-se set(), porque {} cria um dicionário vazio. Tal como nas chaves dos dicionários, os elementos têm de ser imutáveis: um conjunto não pode conter outro conjunto mutável nem listas. A variante imutável chama-se frozenset.

a = {1, 3, 2}
print(a)
a.add(4)
a.discard(3)
print(a)

A primeira escrita mostra {1, 2, 3} ou outra ordem qualquer: os conjuntos não guardam ordem, por isso nunca indexes um conjunto nem assumes a ordem de impressão. O add acrescenta um elemento; o discard remove sem reclamar se o elemento não existir (o método remove levantaria erro nesse caso).

As operações entre conjuntos seguem a matemática: união (|), interseção (&) e diferença (-), com métodos equivalentes union, intersection e difference. Funcionam também misturando conjuntos e listas.

a = {1, 2, 3}
b = {2, 3, 4}
print(a & b)
print(a | b)
print(a - b)
print(a.issubset({1, 2, 3, 4}))

Isto escreve {2, 3}, {1, 2, 3, 4}, {1} e True. A interseção tem os elementos comuns; a união junta sem repetir; a diferença tem o que está em a mas não em b. O método issubset testa se todos os elementos de a estão no outro conjunto.

Exemplo com conjuntos: anagramas

Duas palavras são anagramas quando têm exatamente as mesmas letras com as mesmas repetições, como amor e roma. Ordenar as letras resolve o problema: duas palavras são anagramas quando as suas letras ordenadas coincidem.

def sao_anagramas(a, b):
    return sorted(a) == sorted(b)

print(sao_anagramas('amor', 'roma'))
print(sao_anagramas('amor', 'ramo extra'))

Isto escreve True e False. sorted('amor') devolve ['a', 'm', 'o', 'r'], e sorted('roma') devolve a mesma lista. Repara que um conjunto não serviria aqui: set('amor') == set('roma') também é verdadeiro, mas conjuntos ignoram repetições, por isso set('aab') == set('abb') daria True para palavras que não são anagramas. Escolher a estrutura certa faz parte da solução.

Ver o ficheiro no GitHub

À tua maneira

Escolhe como preferes ler.

Aparência
Ajustar cores e largura
Cor de destaque do tema FEUP
Tipo de letra

Álgebra, lógica e uma ideia de cada vez.

As tuas escolhas ficam guardadas neste navegador.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.