Saltar a contenido

1.7 · Diccionarios y conjuntos

Objetivos. Al terminar este capítulo podrás: modelar datos con diccionarios (clave→valor), modificarlos y recorrerlos; y usar conjuntos para operar con elementos únicos.

Evidencia de logro. Construirás un contador de palabras y una agenda de contactos, eligiendo entre dict, set y las otras estructuras según el problema.

Contexto y motivación

Las listas conservan los elementos en un orden, pero a menudo necesitas buscar un dato mediante un identificador, como el teléfono de una persona o el precio de un producto. El diccionario representa precisamente esa relación entre una clave y un valor. En otros casos solo necesitas conservar elementos únicos, como los clientes que han comprado o las categorías disponibles; para eso está el set.

En una aplicación de IA, los diccionarios pueden representar un registro de cliente, los parámetros de un modelo, una petición HTTP o el JSON de una API. Aprender a elegirlos y recorrerlos facilita el trabajo con esos datos.

Vocabulario

Término Significado
Diccionario (dict) Colección clave → valor ({clave: valor})
Clave Identificador único del valor (debe ser inmutable)
Valor Lo que se guarda (puede ser de cualquier tipo)
Conjunto (set) Colección de elementos únicos y sin orden ({...})
Clave hashable str, int, float o una tuple cuyos elementos también sean hashables; las listas no sirven

Prerrequisitos

1.6 · Listas y tuplas (mutabilidad, tuplas, iterables).

Ruta de estudio

El núcleo obligatorio es crear, consultar, modificar y recorrer diccionarios, usar get, representar datos anidados y aplicar las operaciones básicas de conjuntos. Las comprensiones, la ordenación por valor y los métodos menos frecuentes se trabajan como ampliación después de elegir correctamente la estructura.

1. Crear y acceder a diccionarios

cliente = {"nombre": "Ana", "edad": 20, "ciudad": "Sevilla"}

print(cliente["nombre"])                 # acceso por clave
print(cliente.get("pais", "Desconocido"))  # seguro, con valor por defecto

Salida esperada:

Ana
Desconocido

Un diccionario se escribe entre llaves {} con pares clave: valor separados por comas. cliente["nombre"] devuelve el valor asociado a esa clave; si la clave no existe, Python se detiene con KeyError. cliente.get(clave, por_defecto) devuelve por_defecto si no existe: permite consultar una clave sin que el programa falle.

print(cliente["pais"])   # la clave no existe

Salida esperada (error):

KeyError: 'pais'

2. Modificar diccionarios

persona = {"nombre": "Ana"}
persona["edad"] = 20           # añadir una clave nueva
persona["nombre"] = "María"    # modificar una existente
del persona["edad"]            # borrar una clave

print(persona)

Salida esperada:

{'nombre': 'María'}

Asignar persona[clave] = valor añade la clave si no existe y modifica su valor si ya existe: un diccionario no puede tener dos claves iguales. del elimina la clave y su valor.

3. Métodos y vistas

stock = {"lapiz": 10, "goma": 4}

print(list(stock.keys()))     # claves
print(list(stock.values()))   # valores
print(list(stock.items()))    # pares (clave, valor)
print(stock.get("lapiz"), stock.get("regla", 0))

Salida esperada:

['lapiz', 'goma']
[10, 4]
[('lapiz', 10), ('goma', 4)]
10 0

keys(), values() e items() son vistas que se pueden recorrer o pasar a list(). items() devuelve tuplas (clave, valor), ideal para recorrer. Desde Python 3.7, un diccionario conserva el orden en que insertaste las claves: por eso lapiz sale antes que goma.

4. Recorrer un diccionario

for producto, unidades in stock.items():
    print(producto, unidades)

Salida esperada:

lapiz 10
goma 4

En cada vuelta, items() entrega una tupla (clave, valor) y el desempaquetado de 1.6 la reparte en producto y unidades. Puedes recorrer solo stock.keys(), solo stock.values(), o ambos con items(). Si recorres el diccionario directamente (for producto in stock:), obtienes solo las claves.

5. Diccionarios anidados

Un valor puede ser otro diccionario (o una lista):

usuarios = {
    "u1": {"nombre": "Ana", "edad": 20},
    "u2": {"nombre": "Luis", "edad": 25},
}

print(usuarios["u1"]["nombre"])

Salida esperada:

Ana

Es la estructura típica de un JSON o de datos jerárquicos (un usuario con sus atributos). Para acceder, encadenas claves: usuarios["u1"]["nombre"].

6. Ampliación: comprehension de diccionarios

Igual que las listas, pero con clave: valor:

cuadrados = {x: x ** 2 for x in range(3)}
print(cuadrados)

Salida esperada:

{0: 0, 1: 1, 2: 4}

Útil para construir un diccionario a partir de otra colección: {p: len(p) for p in ["a", "bb"]} → {'a': 1, 'bb': 2}.

7. Ampliación: ordenar, máximo y mínimo (y otros métodos útiles)

A diferencia de las listas, un dict no tiene .sort(). Para ordenarlo lo conviertes en una lista de pares con sorted():

edades = {"Ana": 20, "Luis": 25, "Marta": 18}

print(sorted(edades))          # claves ordenadas
print(sorted(edades.items()))  # pares, ordenados por clave

Salida esperada:

['Ana', 'Luis', 'Marta']
[('Ana', 20), ('Luis', 25), ('Marta', 18)]

sorted(edades) ordena las claves; sorted(edades.items()) devuelve los pares ordenados por clave. Pero a menudo quieres ordenar por el valor (ej. "top de ventas"):

print(sorted(edades.items(), key=lambda x: x[1]))                    # asc por valor
print(sorted(edades.items(), key=lambda x: x[1], reverse=True))      # desc
print(sorted(edades.items(), key=lambda x: x[1], reverse=True)[:2])  # top 2

Salida esperada:

[('Marta', 18), ('Ana', 20), ('Luis', 25)]
[('Luis', 25), ('Ana', 20), ('Marta', 18)]
[('Luis', 25), ('Ana', 20)]

El argumento key=lambda x: x[1] dice "ordena por el segundo elemento de cada pareja (el valor)". [:2] se queda con los 2 primeros → el "top 2".

También puedes pedir el máximo/mínimo por clave o por valor:

print(max(edades, key=edades.get))     # la clave con el mayor valor -> Luis
print(min(edades, key=edades.get))     # la clave con el menor valor -> Marta
print(max(edades.values()))            # el mayor valor -> 25

Salida esperada:

Luis
Marta
25

max(edades, key=edades.get) recorre las claves y compara el resultado de edades.get(clave) para cada una; devuelve la clave cuyo valor es mayor. Fíjate en que edades.get va sin paréntesis: no se llama aquí, se le entrega a max para que la llame con cada clave. max(edades.values()) devuelve el mayor valor directamente. Es el patrón para "¿quién tiene más/la mayor cifra?".

7.1 Otros métodos que conviene conocer

grupo = {"Ana": 20}
print("Luis" in grupo)          # ¿existe la clave?
print(grupo.get("Sara", 0))     # seguro, con valor por defecto

grupo.update({"Luis": 25})      # añade/actualiza varias claves
grupo["Sara"] = 30
print(grupo.pop("Ana"))         # saca y devuelve el valor de una clave
print(grupo)

Salida esperada:

False
0
20
{'Luis': 25, 'Sara': 30}

Útiles que verás a menudo: update(otro) fusiona, pop(clave) extrae y borra, setdefault(clave, valor) añade solo si no existe, copy() hace una copia independiente y clear() vacía el diccionario. Fíjate en que in comprueba las claves, no los valores.

8. Conjuntos (set)

Un set guarda elementos únicos y sin orden:

numeros = {1, 2, 2, 3}
print(sorted(numeros))

vacio = set()          # conjunto vacío: {} crearía un diccionario vacío
print(type(vacio), type({}))

Salida esperada:

[1, 2, 3]
<class 'set'> <class 'dict'>

El duplicado 2 desaparece. Un set responde rápido a "¿está este elemento?". Usamos sorted solo para mostrar una salida estable; el conjunto sigue sin tener orden. Y cuidado con el conjunto vacío: {} es un diccionario vacío; para un conjunto vacío hay que escribir set().

Los set no tienen orden

El orden de un set no está garantizado. Si te importa el orden, usa una lista o un conjunto ordenado (con sorted). No confíes en que los elementos salgan en el orden en que los metiste.

9. Operaciones con conjuntos

a = {1, 2, 3}
b = {2, 3, 4}

print(sorted(a & b))   # intersección: comunes
print(sorted(a | b))   # unión: todos
print(sorted(a - b))   # diferencia: solo en a
print(sorted(a ^ b))   # diferencia simétrica: en uno u otro, no ambos

Salida esperada:

[2, 3]
[1, 2, 3, 4]
[1]
[1, 4]

Estas operaciones responden a preguntas de negocio: ¿qué clientes compraron ambos días (&)? ¿cuáles solo hoy (-)? En Python se escriben con símbolos y son muy rápidas.

10. Aplicación práctica: contador de palabras

texto = "hola mundo hola"
palabras = texto.split()      # divide el texto por los espacios

frecuencia = {}
for palabra in palabras:
    frecuencia[palabra] = frecuencia.get(palabra, 0) + 1

print(frecuencia)

Salida esperada:

{'hola': 2, 'mundo': 1}

texto.split() divide una cadena por los espacios y devuelve la lista ['hola', 'mundo', 'hola'] (lo verás en 1.9 · Cadenas). Después, el patrón frecuencia.get(palabra, 0) + 1 es la forma clásica de contar: si la palabra ya estaba, suma 1 a su cuenta; si no, parte de 0 y suma 1. Lo verás constantemente (contar apariciones, frecuencias, votos).

11. ¿Cuándo usar cada estructura?

Necesitas Estructura
Elementos en orden, que pueden repetirse lista
Buscar por clave (nombre→valor) diccionario
Elementos únicos y comprobar pertenencia conjunto
Datos fijos que van juntos tupla

Regla: si buscas por nombre, dict; si solo quieres unicidad, set; si es una lista ordenada, list.

Errores frecuentes

  • Usar d["clave"] cuando la clave puede no existir (da KeyError); usa d.get(clave, default).
  • Intentar usar una lista como clave de un dict (no es inmutable); usa una tupla.
  • Recorrer un dict con for k in d: y usar d[k] cuando puedes hacer for k, v in d.items():.
  • Creer que un set mantiene el orden de inserción.
  • Escribir {} para crear un conjunto vacío: es un diccionario; usa set().
  • Confundir dict (clave→valor) con set (elementos únicos).

Práctica de transferencia

  1. Crea un dict con 3 productos (nombre → precio) y muestra el precio de uno con get() (con un valor por defecto para uno inexistente).
  2. A partir de texto = "la casa es casa grande y la luz es luz", cuenta la frecuencia de cada palabra.
  3. Con dos set de clientes que compraron el lunes y el martes, muestra quiénes compraron ambos días y quiénes solo el lunes.
  4. Convierte la lista [1, 2, 2, 3, 3, 3] en un set y explica qué pasa con los duplicados.
  5. Crea una agenda: un diccionario cuyas claves sean nombres y cuyos valores sean diccionarios con telefono y email. Muestra el email de una persona y usa get para que buscar a alguien que no está no rompa el programa.

Qué debes justificar: en cada ejercicio, por qué la estructura elegida (dict, set o lista) es la adecuada para esa pregunta.

Producto evaluable

Segunda versión del cuaderno 05_colecciones.py, recibido en 1.6 y ampliado ahora con:

  1. El contador de palabras y la agenda de contactos (un dict anidado con teléfonos/emails), cada uno con su interpretación.
  2. Una celda con las operaciones de set (intersección, unión, diferencia) y su lectura en lenguaje natural.
  3. Una celda final que compare lista, tupla, dict y set en una tabla, con un ejemplo donde cada una tiene sentido.

Formato de entrega: cuaderno marimo ejecutado, con salida esperada, interpretación y conclusión.

Resumen y referencia rápida

Estructura Sintaxis Para qué
Lista [1,2,3] Orden, repetición, mutabilidad
Tupla (1,2,3) Datos fijos, claves de dict
Diccionario {"a": 1} Clave → valor, búsqueda rápida
Conjunto {1,2,3} Elementos únicos, pertenencia

Métodos clave de dict: get, keys, values, items. Operadores de set: &, |, -, ^. Para ordenar: sorted(d.items(), key=lambda x: x[1]); para el extremo por valor: max(d, key=d.get).

Siguiente: 1.8 · Funciones.