Conjuntos e dicionários
Escolher estruturas para pertença, operações de conjuntos e contagens por chave.
Uma lista responde à pergunta “o que está na posição 2?”. Um conjunto responde “este valor está presente?”. Um dicionário responde “qual é o valor associado a esta chave?”. Escolhe a estrutura pela operação de que precisas.
Conjuntos sem repetições
set guarda elementos distintos. {1, 2, 2} tem apenas 1 e 2. Não indexas um conjunto e não deves depender da ordem em que os seus valores aparecem. O conjunto vazio é set(); {} cria um dicionário vazio.
| Operação | Escrita | Significado |
|---|---|---|
| União | a | b | Está em pelo menos um |
| Interseção | a & b | Está nos dois |
| Diferença | a - b | Está em a e não em b |
| Diferença simétrica | a ^ b | Está em exatamente um |
| Inclusão | a <= b | Todos os elementos de a estão em b |
Se a = {"Porto", "Braga"} e b = {"Porto", "Aveiro"}, a interseção é {"Porto"}. A diferença a - b é {"Braga"}. A direção da diferença faz parte do resultado.
add(x) acrescenta um elemento. discard(x) retira-o se existir. remove(x) exige que exista e lança KeyError caso contrário. Usa sorted(conjunto) para obter uma lista numa ordem reprodutível.
Chaves de um dicionário
precos = {"pão": 1.5, "leite": 1.2}
print(precos["pão"])
A chave "pão" identifica um valor, 1.5. Uma chave repetida recebe o último valor atribuído. "pão" in precos testa as chaves, não os preços. precos["arroz"] lança KeyError; precos.get("arroz", 0) devolve zero quando não encontra a chave.
O zero por defeito só é adequado quando significa realmente “não havia unidades contadas” ou outra convenção declarada. Não uses zero para esconder um preço desconhecido.
As chaves e os elementos dos conjuntos têm de ser hashable, ou seja, suportar uma identidade de dispersão estável usada na procura. Inteiros, strings e tuplos de valores hashable servem. Listas e dicionários não servem. Um tuplo que contém uma lista também não serve como chave.
Contar ocorrências
Vamos contar vendas por produto. Para cada produto, lemos a contagem anterior, usando zero quando aparece pela primeira vez, e somamos um.
vendas = ["pão", "leite", "pão", "arroz", "leite", "pão"]
contagens = {}
for produto in vendas:
contagens[produto] = contagens.get(produto, 0) + 1
for produto, quantidade in contagens.items():
print(produto, quantidade)
print(sorted(set(vendas)))Dados de entrada
As contagens são pão 3, leite 2 e arroz 1. O conjunto conserva apenas os nomes distintos. Os dicionários conservam a ordem de inserção das chaves em Python atual, mas a contagem não depende dessa ordem.
keys() percorre chaves, values() percorre valores e items() percorre pares chave-valor. Em for produto, quantidade in contagens.items(), o par de cada iteração é desempacotado nos dois nomes.
Alterar um dicionário e interpretar o retorno
| Operação | Efeito e retorno |
|---|---|
d.pop(chave) | Remove e devolve o valor; KeyError se faltar |
d.pop(chave, valor_padrao) | Devolve o padrão se a chave faltar |
del d[chave] | Remove sem devolver o valor; KeyError se faltar |
d.popitem() | Remove e devolve o último par inserido; KeyError se vazio |
d.setdefault(chave, valor) | Devolve o valor existente ou insere e devolve o padrão |
d.update(outro) | Acrescenta ou substitui pares; devolve None |
d.clear() | Esvazia o dicionário; devolve None |
d.copy() | Devolve uma cópia superficial |
dict.fromkeys(chaves, valor) | Cria chaves associadas ao mesmo objeto de valor |
get lê sem inserir; setdefault pode inserir. update substitui valores de chaves existentes e acrescenta chaves novas. Não atribuas o retorno de update ao dicionário, porque esse retorno é None.
stock = {"A": 2}
chaves = stock.keys()
print(stock.setdefault("A", 9)) # 2, sem substituir
stock.setdefault("B", 4)
stock.update({"A": 3})
print(list(chaves)) # ['A', 'B']
print(stock.popitem()) # ('B', 4)
print(list(chaves)) # ['A']
Em Python atual, keys, items e values devolvem vistas, que refletem alterações ao dicionário, e não listas independentes. Usa list(...) para guardar uma sequência do estado naquele momento. Evita acrescentar ou remover chaves enquanto percorres a vista.
dict.fromkeys(["A", "B"], []) partilha a mesma lista entre os dois valores. Para listas independentes, usa {chave: [] for chave in ["A", "B"]}. Uma cópia superficial de um dicionário também continua a partilhar objetos mutáveis guardados como valores.
Escolher a estrutura
| Precisas de… | Estrutura |
|---|---|
| Conservar a ordem e as repetições das vendas | Lista |
| Guardar um par fixo de coordenadas | Tuplo |
| Saber que produtos apareceram pelo menos uma vez | Conjunto |
| Associar cada produto ao seu preço | Dicionário |
Converter uma lista para conjunto perde repetições e a ordem original. Não é uma operação neutra. Se cada ocorrência representar uma venda, essa conversão já não preserva o número de vendas.
Exercícios
Escolher a direção da diferença
a = 4 e b = 5. Quantos elementos tem a - b?
Primeira pista
Mais uma pista
Ver solução
Erros frequentes
Contar sem perder ocorrências
Escreve contagens(valores), que devolve um dicionário de frequências. O resultado para a, b, a deve ser a: 2 e b: 1. Para lista vazia, devolve dicionário vazio.
def contagens(valores):
return {}
assert contagens([]) == {}
assert contagens(["a", "b", "a"]) == {"a": 2, "b": 1}
assert contagens([3, 3, 3]) == {3: 3}
print("Casos verificados")Dados de entrada
Primeira pista
Mais uma pista
Ver solução
Cria um dicionário vazio, percorre os valores e atualiza a contagem da chave. Devolve o dicionário no fim do ciclo.
Confere a tua resposta:
- Contei cada ocorrência sem converter a entrada em conjunto.
- Tratei a primeira ocorrência com contagem inicial zero.
- Passei os casos vazio e repetido.
Erros frequentes
Usar um conjunto perde repetições; colocar return dentro do ciclo interrompe na primeira ocorrência.
Ler ou inserir sem substituir
stock = {"A": 2}; resultado = stock.setdefault("A", 9).
Quanto vale resultado?
Primeira pista
Mais uma pista
O valor por defeito só é inserido quando a chave está ausente.
Ver solução
Devolve 2 e stock conserva a chave A associada a 2. A chamada não substitui um valor existente.
Erros frequentes
Confundir setdefault com uma atribuição explícita ou com update.