Estructuras anidadas para datos del mundo real: listas de diccionarios y diccionarios de listas

Capítulo 6

Tiempo estimado de lectura: 7 minutos

+ Ejercicio

¿Qué es una estructura anidada y por qué aparece en datos reales?

En datos del mundo real, una sola estructura suele quedarse corta: una entidad tiene varios atributos (por ejemplo, un alumno tiene nombre, id y notas) y además existen relaciones (por ejemplo, una categoría agrupa productos). Una estructura anidada combina colecciones dentro de otras colecciones para reflejar esa realidad: listas de diccionarios (muchas entidades, cada una con atributos) y diccionarios de listas (una clave que agrupa múltiples elementos).

Regla práctica para elegir la forma

  • Lista de diccionarios: cuando tienes una colección de “registros” similares (alumnos, productos, contactos) y recorres o filtras por condiciones.
  • Diccionario de listas: cuando necesitas acceder rápido por una clave de agrupación (categoría, estado, etiqueta) y obtener todos los elementos asociados.
  • Diccionario de diccionarios (variación útil): cuando necesitas acceso directo por id sin recorrer.

Diseño guiado por requisitos: qué consultas necesitas

Antes de escribir código, define las consultas típicas. La forma de los datos debe facilitar esas operaciones.

Checklist de consultas

  • Por id: “dame el alumno con id=10”, “dame el producto SKU=ABC”.
  • Por categoría: “dame productos de ‘lácteos’”.
  • Por rango/condición: “alumnos con promedio > 8”, “productos con stock < 5”.
  • Actualizaciones profundas: “cambiar el teléfono de un contacto”, “agregar una nota a un alumno”, “sumar un producto al carrito”.

Cómo las consultas determinan la estructura

Consulta principalEstructura recomendadaMotivo
Acceso frecuente por iddiccionario[id] -> registroEvita recorrer; acceso directo
Listado/filtrado por condiciónlista de registrosRecorrer y filtrar es natural
Agrupar por categoríadiccionario[categoria] -> listaObtienes el grupo completo por clave
Necesitas ambas (por id y por categoría)Estructuras paralelas o índice adicionalOptimiza dos rutas de acceso

Lista de diccionarios: alumnos con nombre y notas

Modelo base

Representa cada alumno como un diccionario con atributos. La colección completa es una lista.

alumnos = [  {"id": 1, "nombre": "Ana", "notas": [9, 8, 10]},  {"id": 2, "nombre": "Luis", "notas": [7, 6]},  {"id": 3, "nombre": "Mara", "notas": []}]

Diagrama de datos (cajas y flechas)

alumnos (lista)  ├── [0] ──> { id: 1, nombre: "Ana",  notas: [9, 8, 10] }  ├── [1] ──> { id: 2, nombre: "Luis", notas: [7, 6] }  └── [2] ──> { id: 3, nombre: "Mara", notas: [] }

Este tipo de diagrama ayuda a no confundir índices (posición en la lista) con claves (campos del diccionario) y con sublistas (notas).

Acceso en profundidad (leer datos)

  • Nombre del primer alumno: alumnos[0]["nombre"]
  • Segunda nota de Ana: alumnos[0]["notas"][1]
  • Lista de notas de Luis: alumnos[1]["notas"]

Actualización en profundidad (editar y agregar)

Editar un campo (cambiar el nombre del alumno id=2). Como la estructura es una lista, normalmente primero lo encuentras recorriendo:

Continúa en nuestra aplicación.
  • Escuche el audio con la pantalla apagada.
  • Obtenga un certificado al finalizar.
  • ¡Más de 5000 cursos para que explores!
O continúa leyendo más abajo...
Download App

Descargar la aplicación

objetivo_id = 2for alumno in alumnos:  if alumno["id"] == objetivo_id:    alumno["nombre"] = "Luis Alberto"    break

Agregar un elemento a una lista dentro de un diccionario (agregar una nota a Mara):

for alumno in alumnos:  if alumno["nombre"] == "Mara":    alumno["notas"].append(9)    break

Consulta por rango/condición: promedio mayor a 8

Para condiciones, suele ser natural recorrer y filtrar. Si un alumno no tiene notas, decide una regla (por ejemplo, excluirlo).

destacados = []for alumno in alumnos:  notas = alumno["notas"]  if len(notas) == 0:    continue  promedio = sum(notas) / len(notas)  if promedio > 8:    destacados.append(alumno["nombre"])

Mejora cuando “por id” es muy frecuente: índice por id

Si constantemente buscas por id, puedes construir un diccionario auxiliar (un “índice”) para acceso directo, manteniendo la lista para recorridos.

indice_alumnos = {}for alumno in alumnos:  indice_alumnos[alumno["id"]] = alumno# Acceso directoalumno_2 = indice_alumnos[2]alumno_2["notas"].append(10)

Idea clave: el índice apunta al mismo diccionario del alumno, así que actualizar por el índice actualiza el registro original.

Diccionario de listas: categoría → productos

Modelo base

Cuando la consulta típica es “dame todos los productos de una categoría”, un diccionario donde cada clave es la categoría y el valor es una lista de productos funciona muy bien.

catalogo = {  "frutas": [    {"sku": "F01", "nombre": "Manzana", "precio": 1.2},    {"sku": "F02", "nombre": "Banana", "precio": 0.9}  ],  "lacteos": [    {"sku": "L01", "nombre": "Leche", "precio": 1.5}  ],  "panaderia": []}

Diagrama de datos (cajas y flechas)

catalogo (diccionario)  ├── "frutas" ──> [ {sku: F01, ...}, {sku: F02, ...} ]  ├── "lacteos" ──> [ {sku: L01, ...} ]  └── "panaderia" ──> [ ]

Acceso en profundidad

  • Todos los productos de frutas: catalogo["frutas"]
  • Nombre del primer producto de lácteos: catalogo["lacteos"][0]["nombre"]
  • Precio de la banana (recorriendo la lista de la categoría):
precio_banana = Nonefor producto in catalogo["frutas"]:  if producto["sku"] == "F02":    precio_banana = producto["precio"]    break

Actualización en profundidad: editar un campo dentro de un producto

Ejemplo: cambiar el precio de “Leche” en la categoría “lacteos”.

for producto in catalogo["lacteos"]:  if producto["sku"] == "L01":    producto["precio"] = 1.6    break

Agregar un producto a una categoría (lista dentro del diccionario)

nuevo = {"sku": "P10", "nombre": "Pan integral", "precio": 2.3}catalogo["panaderia"].append(nuevo)

Si la categoría podría no existir, define una estrategia: crearla al vuelo.

categoria = "bebidas"producto = {"sku": "B01", "nombre": "Agua", "precio": 0.7}if categoria not in catalogo:  catalogo[categoria] = []catalogo[categoria].append(producto)

Guía paso a paso para diseñar tu estructura anidada

Paso 1: lista las entidades y sus atributos

Ejemplo “alumnos”: atributos: id, nombre, notas. Ejemplo “producto”: sku, nombre, precio, stock.

Paso 2: define relaciones y agrupaciones

Ejemplo “productos por categoría”: una categoría agrupa muchos productos.

Paso 3: escribe 3–5 consultas reales que tu programa debe responder

  • “Buscar alumno por id”
  • “Agregar nota a un alumno”
  • “Listar productos de una categoría”
  • “Encontrar productos con precio en un rango”

Paso 4: elige la forma mínima que haga fáciles esas consultas

  • Si “por id” manda: diccionario por id.
  • Si “por categoría” manda: diccionario de listas.
  • Si necesitas filtrar por condiciones variadas: lista de registros (y opcionalmente índices auxiliares).

Paso 5: dibuja el diagrama de niveles

Haz un esquema tipo “cajas y flechas” y marca qué es lista y qué es diccionario en cada nivel. Esto reduce errores como intentar usar una clave en una lista o un índice en un diccionario.

Ejercicios realistas (lectura y escritura)

1) Carrito de compras (lista de diccionarios + diccionario de totales)

Datos:

carrito = [  {"sku": "F01", "nombre": "Manzana", "precio": 1.2, "cantidad": 3},  {"sku": "L01", "nombre": "Leche", "precio": 1.5, "cantidad": 2}]

Ejercicio A (lectura): calcula el total a pagar (precio * cantidad) recorriendo la lista.

Ejercicio B (escritura): aumenta en 1 la cantidad del producto con sku="L01".

Ejercicio C (escritura profunda): agrega un campo "descuento" al producto “Manzana” y asígnale 0.1 (10%).

2) Inventario por categoría (diccionario de listas + actualización de stock)

Datos:

inventario = {  "frutas": [    {"sku": "F01", "stock": 10},    {"sku": "F02", "stock": 5}  ],  "lacteos": [    {"sku": "L01", "stock": 2}  ]}

Ejercicio A (lectura): lista todos los SKU de “frutas”.

Ejercicio B (escritura profunda): reduce en 1 el stock de sku="L01" dentro de “lacteos”.

Ejercicio C (consulta por rango): encuentra todos los productos con stock <= 2 (recorriendo todas las categorías).

3) Agenda de contactos (lista de diccionarios con listas internas)

Datos:

contactos = [  {"id": 1, "nombre": "Sofía", "telefonos": ["555-0101"], "emails": ["sofia@mail.com"]},  {"id": 2, "nombre": "Diego", "telefonos": [], "emails": []}]

Ejercicio A (lectura): muestra el primer email de Sofía (si existe).

Ejercicio B (escritura profunda): agrega un teléfono a Diego.

Ejercicio C (edición de campo): cambia el nombre del contacto con id=1 a “Sofía R.”.

4) Reto de diseño: ¿una estructura o dos?

Requisito: “Buscar producto por sku” y también “Listar productos por categoría”.

  • Pregunta: ¿usarías solo catalogo[categoria] -> lista o además un indice_sku[sku] -> producto?
  • Ejercicio: dibuja dos diagramas (uno con una sola estructura y otro con índice adicional) y escribe qué operación se vuelve más simple en cada caso.

Ahora responde el ejercicio sobre el contenido:

Si tu programa necesita buscar productos frecuentemente por sku y también listar productos por categoría, ¿qué diseño de datos es el más adecuado?

¡Tienes razón! Felicitaciones, ahora pasa a la página siguiente.

¡Tú error! Inténtalo de nuevo.

Combinar un diccionario de listas por categoría con un índice adicional por sku optimiza ambas consultas: acceso directo por sku sin recorrer y listado rápido por categoría mediante la clave.

Siguiente capítulo

Patrones de operaciones y errores frecuentes al manipular variables, listas y diccionarios

Arrow Right Icon
Portada de libro electrónico gratuitaEstructuras de datos básicas para lógica de programación: variables, listas y diccionarios
75%

Estructuras de datos básicas para lógica de programación: variables, listas y diccionarios

Nuevo curso

8 páginas

Descarga la aplicación para obtener una certificación gratuita y escuchar cursos en segundo plano, incluso con la pantalla apagada.