Dicionários e conjuntos

Associações por chave, frequências, operações de conjuntos e escolha de estruturas.

TLDR

Perguntar sobre esta página

ChatGPTClaudePerplexityGrokGeminiCopiar e abrirDeepSeekCopiar e abrir

Com notas = {"Ana": 15, "Bruno": 12}, consultamos a nota de Ana pelo nome sem saber uma posição; um dicionário associa chaves a valores, enquanto um conjunto guarda apenas os nomes sem contar repetições quando só queremos saber quem participou.

Dicionários, chaves e valores

notas = {"Ana": 15, "Bruno": 12} cria duas associações. notas["Ana"] vale 15. Atribuir novamente à mesma chave substitui o valor, não cria outra entrada. del notas["Bruno"] retira a associação.

Uma chave tem de ser hashable: tem um código numérico, chamado hash, que não muda enquanto for usada como chave.

  • Objetos iguais têm de ter hashes iguais; objetos diferentes podem partilhar um hash.
  • O dicionário usa esse código para encontrar candidatos e a igualdade para distinguir chaves.

Strings, inteiros e tuplos de elementos hashable servem. Listas, dicionários e conjuntos mutáveis não servem como chaves. Os valores não têm essa restrição.

chave in d verifica chaves, não valores. d[chave] lança KeyError se a chave não existir. d.get(chave, padrao) devolve o padrão sem criar a entrada. d.keys(), d.values() e d.items() permitem percorrer chaves, valores e pares. Os dicionários conservam ordem de inserção, mas não ordenam as chaves.

Contar frequências

Queremos contar votos, incluindo nomes repetidos: antes de ver um nome pela primeira vez, a frequência é zero, e cada ocorrência aumenta-a em um.

Contar votos
def frequencias(nomes):
    contagem = {}
    for nome in nomes:
        contagem[nome] = contagem.get(nome, 0) + 1
    return contagem

print(frequencias(["Ana", "Bruno", "Ana", "Ana"]))
print(frequencias([]))
Resultado

Executa o código para ver a saída e os gráficos.

Segue a entrada ["Ana", "Bruno", "Ana", "Ana"]:

Nome visitadoEstado antesAtualizaçãoEstado depois
Ana{}0 + 1{"Ana": 1}
Bruno{"Ana": 1}0 + 1{"Ana": 1, "Bruno": 1}
Ana{"Ana": 1, "Bruno": 1}1 + 1{"Ana": 2, "Bruno": 1}
Ana{"Ana": 2, "Bruno": 1}2 + 1{"Ana": 3, "Bruno": 1}

Depois de cada iteração, o dicionário conta todas as ocorrências já visitadas. Ana fica com 3 e Bruno com 1; a lista vazia produz {}. A função não altera a lista recebida.

Para ordenar a apresentação, percorre sorted(contagem). A ordenação não é necessária para a contagem, só para escolher a ordem de saída.

Dicionários com coleções como valores

Um dicionário pode agrupar vários valores por chave. Se cada cadeira tem uma lista de notas, notas["FP"] pode ser [12, 16]. Alterar essa lista muda o conteúdo alcançável pelo dicionário. Cada chave deve receber uma lista própria: se duas chaves apontarem à mesma lista, um append será visível através de ambas.

notas = {"FP": [12, 16], "MD": [14]}
notas["FP"].append(18)
for cadeira, valores in notas.items():
    print(cadeira, sum(valores) / len(valores))

A saída é FP 15.333333333333334 e MD 14.0. O cálculo exige listas não vazias; se permitires uma lista vazia, define primeiro o resultado nesse caso. Não acrescentes nem retires chaves durante uma iteração sobre o próprio dicionário.

Conjuntos e pertença

set guarda elementos únicos e hashable. set() cria o conjunto vazio; {} cria um dicionário. Um conjunto não tem índices e a sua ordem de iteração não deve determinar a resposta do programa.

Comparar inscrições
python = {"Ana", "Bruno", "Carla"}
robotica = {"Bruno", "Duarte"}
print(sorted(python | robotica))
print(sorted(python & robotica))
print(sorted(python - robotica))
print(sorted(python ^ robotica))
Resultado

Executa o código para ver a saída e os gráficos.

PythonRobóticaAnaCarlaBrunoDuarte
As duas regiões sobrepõem-se apenas em Bruno.

Bruno pertence às duas atividades, por isso fica na interseção; a união recolhe os nomes das duas regiões uma só vez. Para python - robotica, conservamos apenas a parte de Python fora da sobreposição, Ana e Carla, enquanto a diferença simétrica conserva as duas partes exteriores e exclui Bruno.

OperaçãoPerguntaResultado no exemplo
A | BQuem está em pelo menos uma atividade?Ana, Bruno, Carla, Duarte
A & BQuem está em ambas?Bruno
A - BQuem está em A e não em B?Ana, Carla
A ^ BQuem está exatamente numa?Ana, Carla, Duarte

Usámos sorted para tornar a saída determinística. A diferença não é comutativa: robotica - python só contém Duarte. A <= B pergunta se A é subconjunto de B; A < B exige também que sejam diferentes. add acrescenta um elemento; discard retira-o se existir; remove falha se faltar. frozenset é a versão imutável e pode ser uma chave de dicionário.

Escolher a estrutura

Uma lista conserva ordem e repetições. Um tuplo representa uma sequência cujo recipiente não queremos alterar. Um conjunto conserva unicidade. Um dicionário conserva associações e permite contar ou agrupar.

Converter uma lista em conjunto perde a multiplicidade. Se recebeste ['Ana', 'Ana', 'Bruno'], o conjunto permite saber quem votou, mas não quantos votos houve.

Se o resultado exige a ordem original sem repetições, percorre a lista e usa um conjunto auxiliar para reconhecer os nomes já vistos, sem usar a ordem do conjunto como saída: começa com uma lista de resultado e um conjunto vazios, e quando um nome ainda não está no conjunto acrescenta-o às duas coleções, passando ao seguinte se já está. Assim a lista conserva a primeira ocorrência de cada nome.

Exercícios

Escolher uma chave

Qual dos valores pode ser uma chave de dicionário?

A tua resposta

Pista
Os elementos de uma chave em tuplo também têm de ser hashable.
Mais uma pista
Uma lista mutável não cumpre essa condição.
Solução

(2, 3) pode ser chave, porque os dois elementos são inteiros. [2, 3] e (2, [3]) não podem.

  • (2, [3]). A lista interior impede que o tuplo seja hashable.
  • (2, 3). É um tuplo de inteiros hashable.
  • [2, 3]. Listas não são hashable.

Erros frequentes

Achar que qualquer tuplo é hashable, mesmo contendo uma lista.
Voltar à explicação
Construir uma contagem

Obtém o dicionário de frequências para [“azul”, “verde”, “azul”, “vermelho”, “verde”, “azul”]. Explica o papel do zero inicial.

Pista
A primeira ocorrência de cada chave começa em zero antes do incremento.
Mais uma pista
As ocorrências posteriores reutilizam o valor já guardado.
Solução

O resultado é {“azul”: 3, “verde”: 2, “vermelho”: 1}. get(cor, 0) fornece zero quando a chave ainda falta, e a atribuição guarda esse zero mais um.

Confere a tua resposta:

  • Contei azul três vezes e verde duas.
  • Contei vermelho uma vez.
  • Expliquei que o valor por defeito não cria a chave sem atribuição.

Erros frequentes

Deixar a primeira ocorrência com frequência zero.
Voltar à explicação
Comparar grupos de inscrições

Duas atividades têm conjuntos de inscritos A = {1, 2, 3} e B = {3, 4}. Calcula A - B, B - A, A & B e A ^ B, explicando que inscritos seleciona cada operação. Se a lista original de A fosse [1, 1, 2, 3], conseguirias recuperar quantas inscrições fez a pessoa 1 a partir do conjunto?

Pista
Distingue estar nas duas atividades de estar exatamente numa.
Solução

A - B é {1, 2}, os inscritos apenas em A. B - A é {4}, os inscritos apenas em B, por isso a diferença tem direção. A & B é {3}, os inscritos em ambas. A ^ B é {1, 2, 4}, os inscritos exatamente numa.

A conversão de [1, 1, 2, 3] em conjunto elimina a segunda ocorrência de 1. O conjunto não permite recuperar essa contagem; uma lista ou um dicionário de frequências conserva a informação necessária.

Confere a tua resposta:

  • Obtive {1, 2} e {4} nas diferenças.
  • Obtive {3} na interseção e {1, 2, 4} na diferença simétrica.
  • Expliquei a perda das repetições.
Voltar à explicação
Conservar a primeira ocorrência

Define sem_repetidos(nomes): recebe uma lista de strings e devolve outra lista sem repetições, pela ordem da primeira ocorrência. Conserva a lista recebida. Maiúsculas e minúsculas distinguem nomes.

Python
def sem_repetidos(nomes):
    return []
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Ordem da primeira ocorrência
    Código do teste
    print(sem_repetidos(["Bruno", "Ana", "Bruno", "Carla", "Ana"]))
    Esperado:
    ['Bruno', 'Ana', 'Carla']
  2. Lista vazia
    Código do teste
    print(sem_repetidos([]))
    Esperado:
    []
  3. Uma string repetida
    Código do teste
    print(sem_repetidos(["FP", "FP", "FP"]))
    Esperado:
    ['FP']
  4. Maiúsculas distinguem nomes
    Código do teste
    print(sem_repetidos(["Ana", "ana", "Ana"]))
    Esperado:
    ['Ana', 'ana']
  5. Entrada preservada
    Código do teste
    nomes = ["B", "A", "B"]
    print(sem_repetidos(nomes))
    print(nomes)
    Esperado:
    ['B', 'A']
    ['B', 'A', 'B']

Pista

Precisas da ordem da lista e de reconhecer rapidamente o que já apareceu.

Mais uma pista

Mantém um conjunto de nomes vistos e uma lista de resultado. Acrescenta apenas quando o nome ainda falta no conjunto.

Solução

O conjunto decide se já vimos o nome. A lista regista a ordem em que cada nome apareceu pela primeira vez. Nenhuma operação altera nomes.

def sem_repetidos(nomes):
    vistos = set()
    resultado = []
    for nome in nomes:
        if nome not in vistos:
            vistos.add(nome)
            resultado.append(nome)
    return resultado

Erros frequentes

Usar sorted(set(nomes)), que muda a ordem, ou retirar elementos da lista recebida durante o percurso.

Voltar à explicação
Agrupar valores por chave

Define agrupar(pares): recebe uma lista de pares (chave, valor), com chaves hashable, e devolve um dicionário com uma lista própria de valores por chave, pela ordem de chegada. Não alteres a entrada. Com a lista vazia, devolve um dicionário vazio. Por exemplo, [('FP', 12), ('MD', 14), ('FP', 16)] produz {'FP': [12, 16], 'MD': [14]}.

Python
def agrupar(pares):
    return {}
Testes e resultado

Verifica o código para comparar o resultado com os testes.

Testes
  1. Duas chaves
    Código do teste
    print(agrupar([("FP", 12), ("MD", 14), ("FP", 16)]))
    Esperado:
    {'FP': [12, 16], 'MD': [14]}
  2. Vazio
    Código do teste
    print(agrupar([]))
    Esperado:
    {}
  3. Listas distintas por chave e entrada intacta
    Código do teste
    pares = [("FP", 12), ("MD", 14), ("FP", 12)]
    grupos = agrupar(pares)
    grupos["FP"].append(18)
    print(grupos)
    print(pares)
    Esperado:
    {'FP': [12, 12, 18], 'MD': [14]}
    [('FP', 12), ('MD', 14), ('FP', 12)]

Pista

Cria a lista na primeira ocorrência e acrescenta nas seguintes.

Mais uma pista

Testa com uma chave repetida não adjacente, como ("FP", 12) e depois ("FP", 16): sem o teste if chave not in grupos, a segunda ocorrência substitui a lista em vez de acrescentar.

Solução

Para cada par, se a chave falta, cria [valor]; senão, acrescenta o valor à lista existente.

def agrupar(pares):
    grupos = {}
    for chave, valor in pares:
        if chave not in grupos:
            grupos[chave] = []
        grupos[chave].append(valor)
    return grupos

Erros frequentes

Substituir a lista em vez de acrescentar (grupos[chave] = [valor] sempre); partilhar a mesma lista entre chaves com um valor por defeito mutável; alterar chaves durante a iteração do próprio dicionário.

Voltar à explicação

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

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

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

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.