# ─────────────────────────────────────────────
# DICCIONARIOS CON LISTAS DENTRO
# ─────────────────────────────────────────────
# Un valor de un diccionario puede ser cualquier tipo:
# un número, una cadena, una lista, otro diccionario…
alumno = {
'nombre': 'Ana',
'email': 'ana@ana.com',
'notas': [6, 7, 5, 8] # ← el valor es una lista
}
# Para acceder a la lista usamos la clave 'notas'
# y luego la recorremos con un for como cualquier otra lista
print(f"El alumno {alumno['nombre']} tiene las siguientes notas:")
for nota in alumno['notas']:
print(nota)
# 💡 ALTERNATIVA: calcular la media al vuelo
notas = alumno['notas']
print(f"Media: {sum(notas) / len(notas):.1f}") # :.1f → un decimal
# ─────────────────────────────────────────────
# DICCIONARIOS ANIDADOS (diccionario dentro de diccionario)
# ─────────────────────────────────────────────
# Un valor también puede ser otro diccionario.
# Para acceder a sus datos encadenamos corchetes: d['clave1']['clave2']
cliente = {
'nombre': 'Ana',
'email': 'ana@gmail.com',
'direccion': { # ← valor que es otro diccionario
'calle': 'Agla',
'numero': 6,
'cp': '08001',
'ciudad': 'Barcelona'
}
}
# Acceso en cadena: primero entramos en 'direccion', luego en 'calle' y 'numero'
print(f"El cliente {cliente['nombre']} vive en "
f"{cliente['direccion']['calle']} número {cliente['direccion']['numero']}")
# → El cliente Ana vive en Agla número 6
# 💡 ALTERNATIVA: extraer el sub-diccionario en una variable auxiliar
# para no repetir cliente['direccion'] varias veces
dir = cliente['direccion']
print(f"{dir['calle']}, {dir['numero']}, {dir['cp']} {dir['ciudad']}")
# ─────────────────────────────────────────────
# LISTA DE DICCIONARIOS
# ─────────────────────────────────────────────
# Patrón muy habitual: una lista donde cada elemento
# es un diccionario que representa un "registro" (alumno, producto, usuario…)
alumnos = [
{'nombre': 'Ana', 'email': 'ana@gmail.com'},
{'nombre': 'Pep', 'email': 'pep@pepe.com'},
{'nombre': 'Iu', 'email': 'iu@iu.com'}
]
# Recorrer la lista y acceder a una clave de cada diccionario
for alumno in alumnos:
print(alumno['nombre']) # → Ana / Pep / Iu
# Índice negativo -1: último elemento de la lista
print(alumnos[-1]['nombre']) # → Iu
# 💡 ALTERNATIVA: buscar un alumno concreto con next()
ana = next((a for a in alumnos if a['nombre'] == 'Ana'), None)
print(ana) # → {'nombre': 'Ana', 'email': 'ana@gmail.com'}
# · next() devuelve el primer resultado que cumpla la condición
# · el None al final evita un error si no se encuentra ninguno
# 💡 ALTERNATIVA: filtrar varios con comprensión de lista
emails = [a['email'] for a in alumnos]
print(emails) # → ['ana@gmail.com', 'pep@pepe.com', 'iu@iu.com']
# ─────────────────────────────────────────────
# LISTAS DE LISTAS (matriz / cuadrícula)
# ─────────────────────────────────────────────
# Una lista puede contener otras listas → se comporta como una tabla 2D.
# Se accede con dos índices: matriz[fila][columna]
cuadrado = [
[1, 2, 3], # fila 0
[4, 5, 6], # fila 1
[7, 8, 9] # fila 2
]
# Recorrer con for anidado: el primer for va fila a fila,
# el segundo va elemento a elemento dentro de cada fila
for linea in cuadrado:
print(linea) # imprime la fila entera como lista
for numero in linea:
print(numero) # imprime cada número por separado
# Acceso directo a un elemento: [fila][columna]
print(cuadrado[1][1]) # → 5 (fila 1, columna 1 → el centro del cuadrado)
print(cuadrado[0][2]) # → 3 (fila 0, columna 2)
print(cuadrado[2][0]) # → 7 (fila 2, columna 0)
# 💡 ALTERNATIVA: imprimir el cuadrado de forma más visual
for fila in cuadrado:
print(' '.join(str(n) for n in fila))
# → 1 2 3
# → 4 5 6
# → 7 8 9
# ─────────────────────────────────────────────
# ESTRUCTURA DE DATOS COMPLEJA (caso real)
# ─────────────────────────────────────────────
# En proyectos reales anidamos todos estos conceptos:
# diccionarios, listas y sub-diccionarios a varios niveles.
# La clave es ir "entrando" nivel a nivel con corchetes.
empresa = {
'nombre': 'TechCorp',
'departamentos': { # nivel 1: dict de departamentos
'Desarrollo': {
'jefe': 'María Ruiz',
'presupuesto': 150000,
'empleados': [ # nivel 2: lista de empleados
{
'id': 'E001',
'nombre': 'Ana García',
'salario': 35000,
'habilidades': ['Python', 'Django', 'SQL'],
'proyectos': ['WebApp', 'API REST'],
'notas_evaluacion': [8, 9, 8, 9],
},
{
'id': 'E002',
'nombre': 'Carlos López',
'salario': 32000,
'habilidades': ['JavaScript', 'React', 'CSS'],
'proyectos': ['WebApp', 'Dashboard'],
'notas_evaluacion': [7, 8, 7, 6],
},
],
},
'Marketing': {
'jefe': 'Pedro Sanz',
'presupuesto': 80000,
'empleados': [
{
'id': 'E003',
'nombre': 'Lucía Mora',
'salario': 28000,
'habilidades': ['PowerBI', 'Excel', 'Photoshop'],
'proyectos': ['Campaña Q1', 'Redes Sociales'],
'notas_evaluacion': [9, 9, 8, 9],
},
],
},
}
}
# ── Acceso profundo paso a paso ──────────────────────────────────
# Vamos entrando nivel a nivel hasta llegar a lo que queremos:
#
# empresa
# └─ ['departamentos'] → dict de departamentos
# └─ ['Desarrollo'] → dict del departamento
# └─ ['empleados'] → lista de empleados
# └─ [0] → primer empleado (Ana García)
# └─ ['notas_evaluacion'] → [8, 9, 8, 9]
notas = empresa['departamentos']['Desarrollo']['empleados'][0]['notas_evaluacion']
media = sum(notas) / len(notas)
print(media) # → 8.5
# 💡 ALTERNATIVAS Y USOS PRÁCTICOS sobre la estructura 'empresa'
# ── Listar todos los empleados de todos los departamentos
for nombre_depto, depto in empresa['departamentos'].items():
print(f"\n── {nombre_depto} (jefe: {depto['jefe']}) ──")
for emp in depto['empleados']:
print(f" {emp['id']} | {emp['nombre']} | {emp['salario']}€")
# ── Calcular la media de evaluación de cada empleado
for nombre_depto, depto in empresa['departamentos'].items():
for emp in depto['empleados']:
notas = emp['notas_evaluacion']
media = sum(notas) / len(notas)
print(f"{emp['nombre']}: media {media:.1f}")
# ── Acceso seguro con get() cuando no sabemos si la clave existe
salario = empresa['departamentos']['Desarrollo']['empleados'][0].get('bonus', 0)
print(f"Bonus: {salario}€") # → Bonus: 0€ (no existe la clave, devuelve 0)
# ─────────────────────────────────────────────
# FUNCIONES QUE BUSCAN DENTRO DE ESTRUCTURAS ANIDADAS
# ─────────────────────────────────────────────
# Estas funciones reciben el diccionario 'empresa' del ejercicio anterior
# y devuelven una lista con los empleados que coinciden con la búsqueda.
# Si no encuentran nada, devuelven una lista vacía [].
# ─────────────────────────────────────────────
# BUSCAR EMPLEADOS POR NOMBRE
# ─────────────────────────────────────────────
def buscar_empleado(empresa, nombre):
resultado = [] # lista donde iremos guardando los encontrados
departamentos = empresa['departamentos'] # extraemos el dict de departamentos
for departamento in departamentos.values(): # recorremos cada departamento
for empleado in departamento['empleados']: # recorremos cada empleado del departamento
# 'in' sobre una cadena comprueba si nombre está CONTENIDO en empleado['nombre']
# Por eso 'ía' encuentra 'Ana García' y 'María Ruiz'
# Es sensible a mayúsculas: 'ana' NO encontraría 'Ana'
if nombre in empleado['nombre']:
resultado.append(empleado) # añadimos el dict completo del empleado
return resultado # devuelve [] si no encontró nadie, o una lista de coincidencias
# Encuentra a Ana García y María Ruiz porque ambas contienen 'ía'
print(buscar_empleado(empresa, 'ía'))
# Devuelve [] porque no existe ningún 'Carlos González' (hay 'Carlos López')
print(buscar_empleado(empresa, 'Carlos González'))
# 💡 ALTERNATIVA: búsqueda sin distinguir mayúsculas/minúsculas
# Convirtiendo ambas cadenas a minúsculas antes de comparar
def buscar_empleado_v2(empresa, nombre):
resultado = []
for departamento in empresa['departamentos'].values():
for empleado in departamento['empleados']:
if nombre.lower() in empleado['nombre'].lower(): # .lower() → todo minúsculas
resultado.append(empleado)
return resultado
# Ahora 'ana' encuentra 'Ana García', 'ANA' también, etc.
print(buscar_empleado_v2(empresa, 'ana'))
# 💡 ALTERNATIVA: devolver solo el dato que interesa, no el dict entero
def buscar_nombres(empresa, nombre):
return [
emp['nombre'] # solo el nombre
for depto in empresa['departamentos'].values()
for emp in depto['empleados']
if nombre.lower() in emp['nombre'].lower() # búsqueda insensible
]
# Comprensión de lista con dos for anidados: más compacta, misma lógica
# ─────────────────────────────────────────────
# BUSCAR EMPLEADOS POR HABILIDAD
# ─────────────────────────────────────────────
def buscar_empleado_habilidades(empresa, habilidad):
resultado = []
departamentos = empresa['departamentos']
for departamento in departamentos.values():
for empleado in departamento['empleados']:
# Aquí 'in' comprueba si habilidad es un elemento de la LISTA
# empleado['habilidades'] es ['Python', 'Django', 'SQL'] etc.
# Esto busca coincidencia EXACTA: 'React' sí, 'react' NO
if habilidad in empleado['habilidades']:
resultado.append(empleado)
return resultado
# Encuentra a Carlos López porque tiene 'React' en su lista de habilidades
print(buscar_empleado_habilidades(empresa, 'React'))
# Devuelve [] porque nadie tiene 'C#' en sus habilidades
print(buscar_empleado_habilidades(empresa, 'C#'))
# 💡 ALTERNATIVA: búsqueda insensible a mayúsculas en la lista de habilidades
def buscar_empleado_habilidades_v2(empresa, habilidad):
resultado = []
for departamento in empresa['departamentos'].values():
for empleado in departamento['empleados']:
# Convertimos cada habilidad a minúsculas antes de comparar
habilidades_lower = [h.lower() for h in empleado['habilidades']]
if habilidad.lower() in habilidades_lower:
resultado.append(empleado)
return resultado
print(buscar_empleado_habilidades_v2(empresa, 'python')) # Encuentra a Ana García
# 💡 ALTERNATIVA: buscar empleados que tengan VARIAS habilidades a la vez
def buscar_por_varias_habilidades(empresa, habilidades_buscadas):
resultado = []
for departamento in empresa['departamentos'].values():
for empleado in departamento['empleados']:
# set y operador <= comprueban si un conjunto está contenido en otro
# {'Python','SQL'} <= {'Python','Django','SQL'} → True
if set(habilidades_buscadas) <= set(empleado['habilidades']):
resultado.append(empleado['nombre'])
return resultado
print(buscar_por_varias_habilidades(empresa, ['Python', 'SQL']))
# → ['Ana García']
# 💡 ALTERNATIVA: función genérica que busca por CUALQUIER campo
def buscar_por_campo(empresa, campo, valor):
resultado = []
for departamento in empresa['departamentos'].values():
for empleado in departamento['empleados']:
if empleado.get(campo) == valor: # get() evita error si el campo no existe
resultado.append(empleado['nombre'])
return resultado
print(buscar_por_campo(empresa, 'salario', 32000)) # → ['Carlos López']
Patrón general: «recorrer y filtrar»
def buscar_X(estructura, criterio):
resultado = [] # 1. empezamos con lista vacía
for nivel1 in estructura.values(): # 2. recorremos el nivel 1
for item in nivel1['coleccion']: # 3. recorremos el nivel 2
if criterio cumple condicion: # 4. comprobamos el criterio
resultado.append(item) # 5. guardamos el encontrado
return resultado