Patrones Comunes: Recetas Probadas para Problemas Frecuentes
🧭 Navegación:
- Anterior: Control de Bucles
- Siguiente: Diagramas de Flujo
¡Bienvenido al departamento de soluciones eficientes de tu almacén! Ahora que conoces todas las herramientas de control de flujo, es momento de aprender algunos patrones comunes que los programadores experimentados utilizan para resolver problemas frecuentes.
Los patrones comunes son como recetas probadas que combinan condicionales y bucles para resolver tareas específicas de manera eficiente y elegante.
El libro de recetas de tu almacén 📚
Imagínate que tienes un libro de recetas con soluciones optimizadas para las tareas más comunes en tu almacén:
- Recetas de búsqueda: Encontrar elementos específicos
- Recetas de filtrado: Seleccionar elementos que cumplan ciertos criterios
- Recetas de transformación: Modificar elementos de forma sistemática
- Recetas de acumulación: Combinar elementos para obtener resultados
- Recetas de validación: Verificar que los datos cumplan ciertos requisitos
# Una receta en acción
numeros = [10, 25, 3, 8, 42, 15, 7]
# Receta para encontrar el máximo
maximo = numeros[0] # Empezamos asumiendo que el primero es el máximo
for numero in numeros[1:]: # Revisamos el resto
if numero > maximo:
maximo = numero # Actualizamos si encontramos uno mayor
print(f"El número máximo es: {maximo}") # 42
🔍 Mi perspectiva personal: Dominar estos patrones comunes fue un punto de inflexión en mi carrera como programador. Pasé de escribir código que “simplemente funcionaba” a escribir código elegante, eficiente y fácil de mantener. Estos patrones son como las piezas fundamentales de un juego de construcción: una vez que los dominas, puedes combinarlos para resolver problemas cada vez más complejos.
Patrón 1: Búsqueda lineal
Este patrón te permite encontrar un elemento específico en una colección:
# ================================
# BUSCADOR DE ELEMENTOS
# ================================
productos = ["laptop", "mouse", "teclado", "monitor", "auriculares"]
producto_buscado = "teclado"
print("🔍 BUSCADOR DE ELEMENTOS")
print("=" * 25)
print(f"Buscando: {producto_buscado}")
print(f"En lista: {productos}")
print()
# Inicializar variables
encontrado = False
posicion = -1
# Buscar el elemento
for i, producto in enumerate(productos):
print(f"Revisando posición {i}: {producto}")
if producto == producto_buscado:
encontrado = True
posicion = i
print(f" ✅ ¡Elemento encontrado!")
break
print(" ⏭️ Continuando búsqueda...")
# Mostrar resultado
if encontrado:
print(f"\n🎯 {producto_buscado} encontrado en posición {posicion}")
else:
print(f"\n❌ {producto_buscado} no encontrado en la lista")
print("🔚 Búsqueda finalizada")
Variante: Búsqueda de todos los elementos que cumplen un criterio
# ================================
# BUSCADOR DE MÚLTIPLES ELEMENTOS
# ================================
productos = ["laptop", "mouse", "teclado", "monitor", "teclado", "auriculares"]
producto_buscado = "teclado"
print("🔍 BUSCADOR DE MÚLTIPLES ELEMENTOS")
print("=" * 35)
print(f"Buscando todas las ocurrencias de: {producto_buscado}")
print(f"En lista: {productos}")
print()
# Inicializar variables
posiciones = []
# Buscar todas las ocurrencias
for i, producto in enumerate(productos):
print(f"Revisando posición {i}: {producto}")
if producto == producto_buscado:
posiciones.append(i)
print(f" ✅ ¡Elemento encontrado!")
else:
print(" ⏭️ Continuando búsqueda...")
# Mostrar resultado
if posiciones:
print(f"\n🎯 {producto_buscado} encontrado en {len(posiciones)} posiciones: {posiciones}")
else:
print(f"\n❌ {producto_buscado} no encontrado en la lista")
print("🔚 Búsqueda finalizada")
Patrón 2: Filtrado
Este patrón te permite seleccionar elementos que cumplen ciertos criterios:
# ================================
# FILTRADOR DE ELEMENTOS
# ================================
productos = [
{"nombre": "laptop", "precio": 1200, "disponible": True},
{"nombre": "mouse", "precio": 25, "disponible": True},
{"nombre": "teclado", "precio": 50, "disponible": False},
{"nombre": "monitor", "precio": 300, "disponible": True},
{"nombre": "auriculares", "precio": 80, "disponible": False}
]
print("🔍 FILTRADOR DE ELEMENTOS")
print("=" * 25)
# Filtrar productos disponibles
productos_disponibles = []
for producto in productos:
if producto["disponible"]:
productos_disponibles.append(producto)
print(f"Productos disponibles: {len(productos_disponibles)}")
for producto in productos_disponibles:
print(f" • {producto['nombre']} - ${producto['precio']}")
print()
# Filtrar productos económicos (menos de $100)
productos_economicos = []
for producto in productos:
if producto["precio"] < 100:
productos_economicos.append(producto)
print(f"Productos económicos: {len(productos_economicos)}")
for producto in productos_economicos:
print(f" • {producto['nombre']} - ${producto['precio']}")
print()
# Filtrar productos disponibles Y económicos
productos_disponibles_economicos = []
for producto in productos:
if producto["disponible"] and producto["precio"] < 100:
productos_disponibles_economicos.append(producto)
print(f"Productos disponibles y económicos: {len(productos_disponibles_economicos)}")
for producto in productos_disponibles_economicos:
print(f" • {producto['nombre']} - ${producto['precio']}")
print()
# Versión con comprensión de listas
productos_filtrados = [p for p in productos if p["disponible"] and p["precio"] < 100]
print(f"Usando comprensión de listas: {len(productos_filtrados)} productos")
for producto in productos_filtrados:
print(f" • {producto['nombre']} - ${producto['precio']}")
print("🔚 Filtrado finalizado")
Patrón 3: Transformación (Mapeo)
Este patrón te permite aplicar una transformación a cada elemento de una colección:
# ================================
# TRANSFORMADOR DE ELEMENTOS
# ================================
precios = [100, 25, 50, 300, 80]
print("🔄 TRANSFORMADOR DE ELEMENTOS")
print("=" * 30)
print(f"Precios originales: {precios}")
print()
# Aplicar descuento del 10%
precios_con_descuento = []
for precio in precios:
precio_descuento = precio * 0.9 # 10% de descuento
precios_con_descuento.append(precio_descuento)
print(f"Precios con 10% de descuento: {precios_con_descuento}")
print()
# Aplicar impuesto del 21%
precios_con_impuesto = []
for precio in precios:
precio_impuesto = precio * 1.21 # 21% de impuesto
precios_con_impuesto.append(precio_impuesto)
print(f"Precios con 21% de impuesto: {precios_con_impuesto}")
print()
# Versión con comprensión de listas
precios_formateados = [f"${precio:.2f}" for precio in precios]
print(f"Precios formateados: {precios_formateados}")
print()
# Transformación de objetos
productos = [
{"nombre": "laptop", "precio": 1200},
{"nombre": "mouse", "precio": 25},
{"nombre": "teclado", "precio": 50}
]
# Añadir campo de precio con impuesto
for producto in productos:
producto["precio_con_impuesto"] = producto["precio"] * 1.21
print("Productos con precio e impuesto:")
for producto in productos:
print(f" • {producto['nombre']}: ${producto['precio']} (con impuesto: ${producto['precio_con_impuesto']:.2f})")
print("🔚 Transformación finalizada")
Patrón 4: Acumulación
Este patrón te permite combinar elementos para obtener un resultado acumulado:
# ================================
# ACUMULADOR DE VALORES
# ================================
ventas = [1200, 300, 800, 550, 1000, 450]
print("📊 ACUMULADOR DE VALORES")
print("=" * 25)
print(f"Ventas diarias: {ventas}")
print()
# Calcular suma total
total_ventas = 0
for venta in ventas:
total_ventas += venta
print(f"Total de ventas: ${total_ventas}")
print()
# Calcular promedio
promedio_ventas = total_ventas / len(ventas)
print(f"Promedio de ventas: ${promedio_ventas:.2f}")
print()
# Encontrar máximo y mínimo
venta_maxima = ventas[0]
venta_minima = ventas[0]
dia_maximo = 1
dia_minimo = 1
for i, venta in enumerate(ventas, 1):
if venta > venta_maxima:
venta_maxima = venta
dia_maximo = i
if venta < venta_minima:
venta_minima = venta
dia_minimo = i
print(f"Venta máxima: ${venta_maxima} (Día {dia_maximo})")
print(f"Venta mínima: ${venta_minima} (Día {dia_minimo})")
print()
# Contar ventas por encima del promedio
ventas_sobre_promedio = 0
for venta in ventas:
if venta > promedio_ventas:
ventas_sobre_promedio += 1
print(f"Días con ventas sobre el promedio: {ventas_sobre_promedio}")
print("🔚 Análisis finalizado")
Variante: Acumulación con diccionarios
# ================================
# CONTADOR DE FRECUENCIAS
# ================================
votos = ["A", "B", "A", "C", "B", "B", "A", "C", "A", "D", "B", "A"]
print("📊 CONTADOR DE FRECUENCIAS")
print("=" * 25)
print(f"Votos: {votos}")
print()
# Contar frecuencia de cada opción
frecuencias = {}
for voto in votos:
if voto in frecuencias:
frecuencias[voto] += 1
else:
frecuencias[voto] = 1
print("Resultados de la votación:")
for opcion, cantidad in frecuencias.items():
print(f" • Opción {opcion}: {cantidad} votos")
print()
# Encontrar la opción ganadora
opcion_ganadora = ""
max_votos = 0
for opcion, cantidad in frecuencias.items():
if cantidad > max_votos:
max_votos = cantidad
opcion_ganadora = opcion
print(f"🏆 La opción ganadora es: {opcion_ganadora} con {max_votos} votos")
print("🔚 Conteo finalizado")
Patrón 5: Validación
Este patrón te permite verificar que los datos cumplan ciertos requisitos:
# ================================
# VALIDADOR DE DATOS
# ================================
datos_usuario = {
"nombre": "Ana García",
"email": "ana@ejemplo.com",
"edad": 25,
"contraseña": "Abc123!"
}
print("✅ VALIDADOR DE DATOS")
print("=" * 25)
print("Validando datos de usuario:")
for campo, valor in datos_usuario.items():
print(f" • {campo}: {valor}")
print()
# Inicializar variables
errores = []
# Validar nombre
if not datos_usuario["nombre"]:
errores.append("El nombre no puede estar vacío")
elif len(datos_usuario["nombre"]) < 3:
errores.append("El nombre debe tener al menos 3 caracteres")
# Validar email
email = datos_usuario["email"]
if not email:
errores.append("El email no puede estar vacío")
elif "@" not in email or "." not in email:
errores.append("El email debe contener '@' y '.'")
# Validar edad
edad = datos_usuario["edad"]
if not isinstance(edad, int):
errores.append("La edad debe ser un número entero")
elif edad < 18:
errores.append("Debes ser mayor de edad (18+)")
elif edad > 120:
errores.append("La edad parece incorrecta")
# Validar contraseña
contraseña = datos_usuario["contraseña"]
if len(contraseña) < 6:
errores.append("La contraseña debe tener al menos 6 caracteres")
elif not any(c.isupper() for c in contraseña):
errores.append("La contraseña debe contener al menos una mayúscula")
elif not any(c.islower() for c in contraseña):
errores.append("La contraseña debe contener al menos una minúscula")
elif not any(c.isdigit() for c in contraseña):
errores.append("La contraseña debe contener al menos un número")
elif not any(c in "!@#$%^&*" for c in contraseña):
errores.append("La contraseña debe contener al menos un carácter especial")
# Mostrar resultado
if errores:
print("❌ Validación fallida:")
for error in errores:
print(f" • {error}")
else:
print("✅ Todos los datos son válidos")
print("🔚 Validación finalizada")
Patrón 6: Agrupación
Este patrón te permite organizar elementos en grupos según ciertos criterios:
# ================================
# AGRUPADOR DE ELEMENTOS
# ================================
productos = [
{"nombre": "laptop", "categoria": "electrónica", "precio": 1200},
{"nombre": "camisa", "categoria": "ropa", "precio": 25},
{"nombre": "pantalón", "categoria": "ropa", "precio": 35},
{"nombre": "tablet", "categoria": "electrónica", "precio": 300},
{"nombre": "zapatos", "categoria": "ropa", "precio": 80},
{"nombre": "monitor", "categoria": "electrónica", "precio": 250}
]
print("📊 AGRUPADOR DE ELEMENTOS")
print("=" * 25)
print(f"Total de productos: {len(productos)}")
print()
# Agrupar por categoría
productos_por_categoria = {}
for producto in productos:
categoria = producto["categoria"]
if categoria not in productos_por_categoria:
productos_por_categoria[categoria] = []
productos_por_categoria[categoria].append(producto)
# Mostrar grupos
print("Productos agrupados por categoría:")
for categoria, lista_productos in productos_por_categoria.items():
print(f"📁 {categoria.upper()} ({len(lista_productos)} productos):")
for producto in lista_productos:
print(f" • {producto['nombre']} - ${producto['precio']}")
# Calcular precio promedio de la categoría
precio_total = sum(p["precio"] for p in lista_productos)
precio_promedio = precio_total / len(lista_productos)
print(f" 📊 Precio promedio: ${precio_promedio:.2f}")
print()
print("🔚 Agrupación finalizada")
Patrón 7: Combinación de colecciones
Este patrón te permite trabajar con múltiples colecciones relacionadas:
# ================================
# COMBINADOR DE COLECCIONES
# ================================
clientes = [
{"id": 1, "nombre": "Ana García"},
{"id": 2, "nombre": "Carlos López"},
{"id": 3, "nombre": "Elena Martínez"}
]
pedidos = [
{"cliente_id": 1, "producto": "laptop", "cantidad": 1},
{"cliente_id": 2, "producto": "monitor", "cantidad": 2},
{"cliente_id": 1, "producto": "mouse", "cantidad": 1},
{"cliente_id": 3, "producto": "teclado", "cantidad": 1},
{"cliente_id": 2, "producto": "auriculares", "cantidad": 1},
{"cliente_id": 1, "producto": "tablet", "cantidad": 1}
]
print("🔄 COMBINADOR DE COLECCIONES")
print("=" * 30)
print(f"Clientes: {len(clientes)}")
print(f"Pedidos: {len(pedidos)}")
print()
# Crear informe de pedidos por cliente
print("INFORME DE PEDIDOS POR CLIENTE:")
print("=" * 30)
for cliente in clientes:
cliente_id = cliente["id"]
nombre = cliente["nombre"]
print(f"👤 Cliente: {nombre}")
# Encontrar todos los pedidos de este cliente
pedidos_cliente = []
for pedido in pedidos:
if pedido["cliente_id"] == cliente_id:
pedidos_cliente.append(pedido)
# Mostrar pedidos
if pedidos_cliente:
print(f" 📦 Pedidos ({len(pedidos_cliente)}):")
for i, pedido in enumerate(pedidos_cliente, 1):
print(f" {i}. {pedido['producto']} (x{pedido['cantidad']})")
else:
print(" ❌ No tiene pedidos")
print()
print("🔚 Informe finalizado")
Patrón 8: Procesamiento por lotes
Este patrón te permite procesar grandes cantidades de datos en grupos más pequeños:
# ================================
# PROCESADOR POR LOTES
# ================================
datos = list(range(1, 101)) # Lista de números del 1 al 100
tamaño_lote = 10
print("📦 PROCESADOR POR LOTES")
print("=" * 25)
print(f"Total de elementos: {len(datos)}")
print(f"Tamaño de lote: {tamaño_lote}")
print()
# Procesar por lotes
total_lotes = (len(datos) + tamaño_lote - 1) // tamaño_lote # Redondeo hacia arriba
for i in range(total_lotes):
# Calcular índices del lote actual
inicio = i * tamaño_lote
fin = min(inicio + tamaño_lote, len(datos))
lote_actual = datos[inicio:fin]
print(f"Procesando lote {i+1}/{total_lotes} (elementos {inicio+1}-{fin}):")
# Procesar cada elemento del lote
suma_lote = 0
for elemento in lote_actual:
suma_lote += elemento
print(f" • Elementos: {lote_actual}")
print(f" • Suma del lote: {suma_lote}")
print()
print("🔚 Procesamiento por lotes finalizado")
Comprueba tu comprensión 🧠
-
¿Qué patrón utilizarías para encontrar todos los productos con precio mayor a $100?
-
¿Cuál es la diferencia entre el patrón de transformación y el patrón de acumulación?
-
Escribe un código que utilice el patrón de validación para verificar si una contraseña cumple con los siguientes requisitos: al menos 8 caracteres, al menos una mayúscula, al menos un número.
-
¿Qué patrón utilizarías para contar cuántas veces aparece cada letra en una cadena de texto?
Soluciones
-
Para encontrar todos los productos con precio mayor a $100, utilizaría el patrón de filtrado:
productos = [ {"nombre": "laptop", "precio": 1200}, {"nombre": "mouse", "precio": 25}, {"nombre": "teclado", "precio": 50}, {"nombre": "monitor", "precio": 300} ] productos_caros = [] for producto in productos: if producto["precio"] > 100: productos_caros.append(producto) # Alternativa con comprensión de listas: # productos_caros = [p for p in productos if p["precio"] > 100]
-
Diferencia entre transformación y acumulación:
- Transformación (Mapeo): Aplica una operación a cada elemento de una colección para crear una nueva colección con los resultados. La cantidad de elementos de entrada y salida es la misma.
- Acumulación: Combina todos los elementos de una colección para producir un único resultado (como una suma, promedio, máximo, etc.).
-
Código para validar una contraseña:
def validar_contraseña(contraseña): errores = [] if len(contraseña) < 8: errores.append("La contraseña debe tener al menos 8 caracteres") if not any(c.isupper() for c in contraseña): errores.append("La contraseña debe contener al menos una mayúscula") if not any(c.isdigit() for c in contraseña): errores.append("La contraseña debe contener al menos un número") return errores # Ejemplo de uso contraseña = "password123" errores = validar_contraseña(contraseña) if errores: print("Contraseña inválida:") for error in errores: print(f"- {error}") else: print("Contraseña válida")
-
Para contar cuántas veces aparece cada letra en una cadena de texto, utilizaría el patrón de acumulación con diccionarios (contador de frecuencias):
texto = "programacion" frecuencias = {} for letra in texto: if letra in frecuencias: frecuencias[letra] += 1 else: frecuencias[letra] = 1 # Alternativa con defaultdict: # from collections import defaultdict # frecuencias = defaultdict(int) # for letra in texto: # frecuencias[letra] += 1
Ejercicio práctico: Sistema de análisis de ventas
# ================================
# SISTEMA DE ANÁLISIS DE VENTAS
# ================================
ventas = [
{"fecha": "2023-01-15", "producto": "laptop", "categoria": "electrónica", "cantidad": 1, "precio": 1200},
{"fecha": "2023-01-15", "producto": "mouse", "categoria": "electrónica", "cantidad": 3, "precio": 25},
{"fecha": "2023-01-16", "producto": "camisa", "categoria": "ropa", "cantidad": 2, "precio": 30},
{"fecha": "2023-01-17", "producto": "laptop", "categoria": "electrónica", "cantidad": 1, "precio": 1200},
{"fecha": "2023-01-18", "producto": "pantalón", "categoria": "ropa", "cantidad": 1, "precio": 50},
{"fecha": "2023-01-19", "producto": "monitor", "categoria": "electrónica", "cantidad": 2, "precio": 300},
{"fecha": "2023-01-20", "producto": "zapatos", "categoria": "ropa", "cantidad": 1, "precio": 80},
{"fecha": "2023-01-20", "producto": "teclado", "categoria": "electrónica", "cantidad": 4, "precio": 45}
]
print("📊 SISTEMA DE ANÁLISIS DE VENTAS")
print("=" * 35)
print(f"Total de transacciones: {len(ventas)}")
print()
# 1. Calcular ventas totales (patrón de acumulación)
total_ventas = 0
total_unidades = 0
for venta in ventas:
importe = venta["cantidad"] * venta["precio"]
total_ventas += importe
total_unidades += venta["cantidad"]
print(f"💰 VENTAS TOTALES: ${total_ventas:,.2f}")
print(f"📦 UNIDADES VENDIDAS: {total_unidades}")
print()
# 2. Agrupar ventas por categoría (patrón de agrupación)
ventas_por_categoria = {}
for venta in ventas:
categoria = venta["categoria"]
importe = venta["cantidad"] * venta["precio"]
if categoria in ventas_por_categoria:
ventas_por_categoria[categoria] += importe
else:
ventas_por_categoria[categoria] = importe
print("📊 VENTAS POR CATEGORÍA:")
for categoria, importe in ventas_por_categoria.items():
porcentaje = (importe / total_ventas) * 100
print(f" • {categoria}: ${importe:,.2f} ({porcentaje:.1f}%)")
print()
# 3. Encontrar el producto más vendido (patrones de acumulación y búsqueda)
ventas_por_producto = {}
for venta in ventas:
producto = venta["producto"]
cantidad = venta["cantidad"]
if producto in ventas_por_producto:
ventas_por_producto[producto] += cantidad
else:
ventas_por_producto[producto] = cantidad
producto_mas_vendido = ""
max_cantidad = 0
for producto, cantidad in ventas_por_producto.items():
if cantidad > max_cantidad:
max_cantidad = cantidad
producto_mas_vendido = producto
print(f"🏆 PRODUCTO MÁS VENDIDO: {producto_mas_vendido} ({max_cantidad} unidades)")
print()
# 4. Analizar ventas por día (patrón de agrupación)
ventas_por_dia = {}
for venta in ventas:
fecha = venta["fecha"]
importe = venta["cantidad"] * venta["precio"]
if fecha in ventas_por_dia:
ventas_por_dia[fecha]["importe"] += importe
ventas_por_dia[fecha]["transacciones"] += 1
else:
ventas_por_dia[fecha] = {"importe": importe, "transacciones": 1}
print("📅 VENTAS POR DÍA:")
for fecha, datos in ventas_por_dia.items():
print(f" • {fecha}: ${datos['importe']:,.2f} ({datos['transacciones']} transacciones)")
print("🔚 Análisis finalizado")
¡Ahora tienes un arsenal de patrones comunes para resolver problemas frecuentes en programación! En el próximo capítulo, aprenderás a visualizar el flujo de tus programas con diagramas.
🧭 Navegación:
- Anterior: Control de Bucles
- Siguiente: Diagramas de Flujo
Capítulos de esta sección:
- Introducción a Estructuras de Control
- Condicionales
- Bucles For
- Bucles While
- Control de Bucles
- Patrones Comunes (página actual)
- Diagramas de Flujo
- Quiz: Estructuras de Control