Map, Filter y Reduce en Python: Programación Funcional Completa

Contenido
¿Qué son map, filter y reduce?
Map, filter y reduce son tres funciones fundamentales de la programación funcional que te permiten procesar colecciones de datos de manera elegante y eficiente. Estas funciones de orden superior aplican operaciones a iterables (listas, tuplas, etc.) sin necesidad de escribir bucles explícitos.
Concepto clave: En lugar de usar bucles for tradicionales para procesar datos, usas estas funciones que expresan qué quieres hacer, no cómo hacerlo. Esto hace tu código más declarativo, conciso y fácil de entender.

Las tres funciones:
- map() – Transforma cada elemento aplicando una función
- filter() – Filtra elementos que cumplen una condición
- reduce() – Reduce todos los elementos a un solo valor acumulativo
Estas funciones son pilares de la programación funcional y se combinan perfectamente con funciones lambda.
La función map() en Python
map() aplica una función a cada elemento de un iterable y retorna un iterador con los resultados.
Sintaxis
map(función, iterable1, iterable2, ...)Ejemplo básico
# Elevar al cuadrado cada número
numeros = [1, 2, 3, 4, 5]
cuadrados = map(lambda x: x ** 2, numeros)
# map retorna un iterador, convertir a lista
print(list(cuadrados))  # [1, 4, 9, 16, 25]Comparación con bucle for:
# Con bucle for tradicional
numeros = [1, 2, 3, 4, 5]
cuadrados = []
for x in numeros:
    cuadrados.append(x ** 2)
# Con map (más conciso)
cuadrados = list(map(lambda x: x ** 2, numeros))Map con funciones regulares
No estás limitado a lambdas, puedes usar cualquier función:
def cuadrado(x):
    return x ** 2
numeros = [1, 2, 3, 4, 5]
resultado = list(map(cuadrado, numeros))
print(resultado)  # [1, 4, 9, 16, 25]
Map con funciones built-in
# Convertir strings a enteros
strings = ["1", "2", "3", "4", "5"]
enteros = list(map(int, strings))
print(enteros)  # [1, 2, 3, 4, 5]
# Convertir a mayúsculas
palabras = ["hola", "mundo", "python"]
mayusculas = list(map(str.upper, palabras))
print(mayusculas)  # ['HOLA', 'MUNDO', 'PYTHON']
# Calcular longitudes
nombres = ["Ana", "Carlos", "Beatriz"]
longitudes = list(map(len, nombres))
print(longitudes)  # [3, 6, 8]Map con múltiples iterables
Puedes pasar múltiples iterables a map():
# Sumar elementos de dos listas
lista1 = [1, 2, 3, 4]
lista2 = [10, 20, 30, 40]
sumas = list(map(lambda x, y: x + y, lista1, lista2))
print(sumas)  # [11, 22, 33, 44]
# Multiplicar tres listas
a = [1, 2, 3]
b = [10, 20, 30]
c = [100, 200, 300]
productos = list(map(lambda x, y, z: x * y * z, a, b, c))
print(productos)  # [1000, 8000, 27000]Casos de uso prácticos con map()
# 1. Procesar precios con IVA
precios = [10, 20, 30, 40, 50]
con_iva = list(map(lambda p: p * 1.21, precios))
print(con_iva)  # [12.1, 24.2, 36.3, 48.4, 60.5]
# 2. Convertir temperaturas Celsius a Fahrenheit
celsius = [0, 10, 20, 30, 40]
fahrenheit = list(map(lambda c: (c * 9/5) + 32, celsius))
print(fahrenheit)  # [32.0, 50.0, 68.0, 86.0, 104.0]
# 3. Extraer información de diccionarios
usuarios = [
    {"nombre": "Ana", "edad": 25},
    {"nombre": "Carlos", "edad": 30},
    {"nombre": "Beatriz", "edad": 28}
]
nombres = list(map(lambda u: u["nombre"], usuarios))
print(nombres)  # ['Ana', 'Carlos', 'Beatriz']
# 4. Formatear strings
numeros = [1, 2, 3, 4, 5]
formateados = list(map(lambda n: f"Número: {n:02d}", numeros))
print(formateados)
# ['Número: 01', 'Número: 02', 'Número: 03', 'Número: 04', 'Número: 05']La función filter() en Python
filter() filtra elementos de un iterable que cumplen una condición (donde la función retorna True).

Sintaxis
filter(función_booleana, iterable)Ejemplo básico
# Filtrar números pares
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pares = filter(lambda x: x % 2 == 0, numeros)
print(list(pares))  # [2, 4, 6, 8, 10]Comparación con bucle for:
# Con bucle for tradicional
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pares = []
for x in numeros:
    if x % 2 == 0:
        pares.append(x)
# Con filter (más conciso)
pares = list(filter(lambda x: x % 2 == 0, numeros))Ejemplos prácticos con filter()
# 1. Filtrar números positivos
numeros = [-5, -2, 0, 3, 7, -1, 10]
positivos = list(filter(lambda x: x > 0, numeros))
print(positivos)  # [3, 7, 10]
# 2. Filtrar strings por longitud
palabras = ["a", "bb", "ccc", "dddd", "ee", "ffffff"]
largas = list(filter(lambda s: len(s) >= 3, palabras))
print(largas)  # ['ccc', 'dddd', 'ffffff']
# 3. Filtrar valores None o vacíos
valores = [0, 1, "", "texto", None, [], [1, 2], False, True]
validos = list(filter(None, valores))  # None filtra valores "falsy"
print(validos)  # [1, 'texto', [1, 2], True]
# Alternativa más explícita
validos2 = list(filter(lambda x: x, valores))
print(validos2)  # [1, 'texto', [1, 2], True]Filter con funciones regulares
def es_par(numero):
    return numero % 2 == 0
numeros = [1, 2, 3, 4, 5, 6, 7, 8]
pares = list(filter(es_par, numeros))
print(pares)  # [2, 4, 6, 8]
# Validación de emails
def email_valido(email):
    return "@" in email and "." in email.split("@")[1]
emails = ["user@test.com", "invalid", "otro@mail.com", "malformed@"]
validos = list(filter(email_valido, emails))
print(validos)  # ['user@test.com', 'otro@mail.com']Casos de uso avanzados con filter()
# 1. Filtrar productos por rango de precio
productos = [
    {"nombre": "A", "precio": 10},
    {"nombre": "B", "precio": 25},
    {"nombre": "C", "precio": 50},
    {"nombre": "D", "precio": 75},
    {"nombre": "E", "precio": 100}
]
rango_medio = list(filter(lambda p: 20 <= p["precio"] <= 60, productos))
print([p["nombre"] for p in rango_medio])  # ['B', 'C']
# 2. Filtrar usuarios adultos
usuarios = [
    {"nombre": "Ana", "edad": 17},
    {"nombre": "Carlos", "edad": 25},
    {"nombre": "Beatriz", "edad": 15},
    {"nombre": "David", "edad": 30}
]
adultos = list(filter(lambda u: u["edad"] >= 18, usuarios))
print([u["nombre"] for u in adultos])  # ['Carlos', 'David']
# 3. Filtrar archivos por extensión
archivos = ["documento.pdf", "imagen.jpg", "texto.txt", "foto.png", "reporte.pdf"]
pdfs = list(filter(lambda f: f.endswith(".pdf"), archivos))
print(pdfs)  # ['documento.pdf', 'reporte.pdf']
# 4. Filtrar números primos (simple)
def es_primo(n):
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True
numeros = range(1, 21)
primos = list(filter(es_primo, numeros))
print(primos)  # [2, 3, 5, 7, 11, 13, 17, 19]La función reduce() en Python
reduce() aplica una función acumulativa a los elementos de un iterable, reduciendo todo a un solo valor.

Importante: reduce() está en el módulo functools, debes importarla:
from functools import reduceSintaxis
reduce(función_acumulativa, iterable, [valor_inicial])¿Cómo funciona reduce()?
from functools import reduce
# Ejemplo visual del proceso
numeros = [1, 2, 3, 4, 5]
# reduce aplica la función así:
# Paso 1: 1 + 2 = 3
# Paso 2: 3 + 3 = 6
# Paso 3: 6 + 4 = 10
# Paso 4: 10 + 5 = 15
suma = reduce(lambda a, b: a + b, numeros)
print(suma)  # 15Ejemplos básicos
from functools import reduce
# Sumar todos los números
numeros = [1, 2, 3, 4, 5]
suma = reduce(lambda a, b: a + b, numeros)
print(suma)  # 15
# Multiplicar todos los números
producto = reduce(lambda a, b: a * b, numeros)
print(producto)  # 120
# Encontrar el máximo
maximo = reduce(lambda a, b: a if a > b else b, numeros)
print(maximo)  # 5
# Encontrar el mínimo
minimo = reduce(lambda a, b: a if a < b else b, numeros)
print(minimo)  # 1Reduce con valor inicial
from functools import reduce
# Sin valor inicial
numeros = [1, 2, 3, 4, 5]
suma = reduce(lambda a, b: a + b, numeros)
print(suma)  # 15
# Con valor inicial de 100
suma_con_inicial = reduce(lambda a, b: a + b, numeros, 100)
print(suma_con_inicial)  # 115 (100 + 15)
# Útil para listas vacías (evita errores)
lista_vacia = []
resultado = reduce(lambda a, b: a + b, lista_vacia, 0)
print(resultado)  # 0 (no da error)Casos de uso prácticos con reduce()
from functools import reduce
# 1. Concatenar strings
palabras = ["Python", " ", "es", " ", "genial"]
frase = reduce(lambda a, b: a + b, palabras)
print(frase)  # Python es genial
# 2. Aplanar lista de listas
listas = [[1, 2], [3, 4], [5, 6]]
plana = reduce(lambda a, b: a + b, listas)
print(plana)  # [1, 2, 3, 4, 5, 6]
# 3. Construir diccionario desde pares
pares = [("a", 1), ("b", 2), ("c", 3)]
diccionario = reduce(
    lambda d, par: {**d, par[0]: par[1]},
    pares,
    {}
)
print(diccionario)  # {'a': 1, 'b': 2, 'c': 3}
# 4. Calcular factorial
def factorial(n):
    return reduce(lambda a, b: a * b, range(1, n + 1), 1)
print(factorial(5))   # 120
print(factorial(10))  # 3628800
# 5. Contar frecuencias
palabras = ["hola", "mundo", "hola", "python", "mundo", "hola"]
frecuencias = reduce(
    lambda d, palabra: {**d, palabra: d.get(palabra, 0) + 1},
    palabras,
    {}
)
print(frecuencias)  # {'hola': 3, 'mundo': 2, 'python': 1}Profundiza en programación funcional avanzada
En el libro Python a fondo encontrarás patrones avanzados, composición de funciones, y proyectos reales con programación funcional.
Combinando map, filter y reduce
El verdadero poder emerge cuando combinas estas funciones:

Pipeline de transformación de datos
from functools import reduce
# Lista de ventas
ventas = [
    {"producto": "A", "cantidad": 5, "precio": 10},
    {"producto": "B", "cantidad": 3, "precio": 25},
    {"producto": "C", "cantidad": 0, "precio": 50},  # Sin stock
    {"producto": "D", "cantidad": 8, "precio": 15},
    {"producto": "E", "cantidad": 0, "precio": 100}  # Sin stock
]
# 1. Filtrar productos con stock
con_stock = filter(lambda v: v["cantidad"] > 0, ventas)
# 2. Calcular total de cada venta
totales = map(lambda v: v["cantidad"] * v["precio"], con_stock)
# 3. Sumar todos los totales
total_general = reduce(lambda a, b: a + b, totales, 0)
print(total_general)  # 245 (50 + 75 + 120)Ejemplo completo: Procesamiento de datos de estudiantes
from functools import reduce
estudiantes = [
    {"nombre": "Ana", "notas": [85, 90, 78]},
    {"nombre": "Carlos", "notas": [92, 88, 95]},
    {"nombre": "Beatriz", "notas": [75, 80, 70]},
    {"nombre": "David", "notas": [60, 55, 58]},
    {"nombre": "Elena", "notas": [95, 98, 92]}
]
# Paso 1: Calcular promedio de cada estudiante con map
con_promedio = list(map(
    lambda e: {**e, "promedio": sum(e["notas"]) / len(e["notas"])},
    estudiantes
))
# Paso 2: Filtrar estudiantes aprobados (promedio >= 70)
aprobados = list(filter(
    lambda e: e["promedio"] >= 70,
    con_promedio
))
# Paso 3: Calcular el promedio general de aprobados con reduce
if aprobados:
    promedio_general = reduce(
        lambda acc, e: acc + e["promedio"],
        aprobados,
        0
    ) / len(aprobados)
    print(f"Estudiantes aprobados: {[e['nombre'] for e in aprobados]}")
    print(f"Promedio general: {promedio_general:.2f}")
# Estudiantes aprobados: ['Ana', 'Carlos', 'Beatriz', 'Elena']
# Promedio general: 86.08Encadenar operaciones
from functools import reduce
# Procesar lista de números
numeros = range(1, 11)  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Pipeline: filtrar pares -> elevar al cuadrado -> sumar
resultado = reduce(
    lambda a, b: a + b,
    map(
        lambda x: x ** 2,
        filter(lambda x: x % 2 == 0, numeros)
    ),
    0
)
print(resultado)  # 220 (4 + 16 + 36 + 64 + 100)
# Versión más legible con variables intermedias
pares = filter(lambda x: x % 2 == 0, numeros)
cuadrados = map(lambda x: x ** 2, pares)
suma = reduce(lambda a, b: a + b, cuadrados, 0)
print(suma)  # 220map(), filter(), reduce() vs Listas por comprensión
Las comprensiones de listas son una alternativa pythónica a map y filter:
Map vs Comprensión de lista
# Con map
numeros = [1, 2, 3, 4, 5]
cuadrados_map = list(map(lambda x: x ** 2, numeros))
# Con comprensión de lista (más pythónico)
cuadrados_comp = [x ** 2 for x in numeros]
# Ambos producen: [1, 4, 9, 16, 25]Filter vs Comprensión de lista
# Con filter
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
pares_filter = list(filter(lambda x: x % 2 == 0, numeros))
# Con comprensión de lista (más pythónico)
pares_comp = [x for x in numeros if x % 2 == 0]
# Ambos producen: [2, 4, 6, 8, 10]Map + Filter combinados
# Con map y filter
numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
resultado_func = list(map(
    lambda x: x ** 2,
    filter(lambda x: x % 2 == 0, numeros)
))
# Con comprensión de lista (más legible)
resultado_comp = [x ** 2 for x in numeros if x % 2 == 0]
# Ambos producen: [4, 16, 36, 64, 100]¿Cuándo usar cada uno?
Usa comprensiones de lista cuando:
- La operación es simple y clara
- Trabajas solo con listas
- Quieres código más pythónico y legible
Usa map/filter/reduce cuando:
- Ya tienes funciones definidas para reutilizar
- Trabajas con múltiples iterables simultáneamente
- Necesitas procesamiento «lazy» (sin convertir a lista)
- Estás haciendo programación funcional explícita
# ✅ Bueno con comprensión
cuadrados = [x ** 2 for x in range(10)]
# ✅ Bueno con map (función reutilizable)
def procesar_complejo(x):
    return x ** 2 + 2 * x + 1
resultados = list(map(procesar_complejo, range(10)))Iteradores vs Listas
Map y filter retornan iteradores, no listas. Esto tiene ventajas de memoria:
# Iterador (lazy evaluation)
numeros = range(1, 1000000)
cuadrados_iter = map(lambda x: x ** 2, numeros)
# No se calcula nada todavía
# Solo calcula cuando iteras
primeros_3 = []
for i, cuad in enumerate(cuadrados_iter):
    if i >= 3:
        break
    primeros_3.append(cuad)
print(primeros_3)  # [1, 4, 9]
# Para convertir todo a lista (usa memoria)
# cuadrados_lista = list(cuadrados_iter)  # ¡Cuidado con listas grandes!Ventajas de iteradores
# 1. Eficiencia de memoria
import sys
# Lista (usa memoria)
lista = [x ** 2 for x in range(1000)]
print(sys.getsizeof(lista))  # ~9000 bytes
# Iterador (usa poca memoria)
iterador = map(lambda x: x ** 2, range(1000))
print(sys.getsizeof(iterador))  # ~56 bytes
# 2. Procesamiento on-demand
def procesar(x):
    print(f"Procesando {x}")
    return x ** 2
# Con map - no procesa hasta que iteras
numeros_map = map(procesar, [1, 2, 3])
print("Map creado")  # No imprime "Procesando"
print(next(numeros_map))  # Ahora sí: "Procesando 1" -> 1Casos de uso del mundo real
1. Procesamiento de logs
from functools import reduce
logs = [
    "ERROR: Conexión fallida",
    "INFO: Usuario conectado",
    "ERROR: Timeout",
    "WARNING: Uso alto de CPU",
    "ERROR: Fallo en base de datos",
    "INFO: Tarea completada"
]
# Filtrar solo errores
errores = list(filter(lambda log: log.startswith("ERROR"), logs))
# Contar errores con reduce
num_errores = reduce(lambda acc, _: acc + 1, errores, 0)
print(f"Errores encontrados: {num_errores}")  # 3
print(errores)2. Análisis de ventas
from functools import reduce
ventas = [
    {"mes": "Enero", "ventas": [100, 150, 200]},
    {"mes": "Febrero", "ventas": [120, 180, 210]},
    {"mes": "Marzo", "ventas": [90, 160, 190]}
]
# Calcular total por mes con map
ventas_por_mes = list(map(
    lambda v: {"mes": v["mes"], "total": sum(v["ventas"])},
    ventas
))
# Filtrar meses con ventas > 400
buenos_meses = list(filter(
    lambda v: v["total"] > 400,
    ventas_por_mes
))
# Total general con reduce
total_general = reduce(
    lambda acc, v: acc + v["total"],
    ventas_por_mes,
    0
)
print(f"Buenos meses: {[m['mes'] for m in buenos_meses]}")
print(f"Total general: {total_general}")3. Transformación de datos API
# Datos de una API
usuarios_api = [
    {"user_name": "ana garcia", "user_age": 25, "user_active": True},
    {"user_name": "carlos lopez", "user_age": 17, "user_active": True},
    {"user_name": "beatriz torres", "user_age": 30, "user_active": False},
    {"user_name": "david martin", "user_age": 22, "user_active": True}
]
# Transformar con map (normalizar nombres de campos y capitalizar)
usuarios_norm = list(map(
    lambda u: {
        "nombre": u["user_name"].title(),
        "edad": u["user_age"],
        "activo": u["user_active"]
    },
    usuarios_api
))
# Filtrar adultos activos
adultos_activos = list(filter(
    lambda u: u["edad"] >= 18 and u["activo"],
    usuarios_norm
))
print(adultos_activos)
# [{'nombre': 'Ana Garcia', 'edad': 25, 'activo': True},
#  {'nombre': 'David Martin', 'edad': 22, 'activo': True}]Puntos clave para recordar
Map, filter y reduce son herramientas poderosas de programación funcional que hacen tu código más expresivo y conciso:
- map() – Transforma cada elemento aplicando una función
- filter() – Filtra elementos basándose en una condición booleana
- reduce() – Reduce todos los elementos a un solo valor acumulativo (importar de functools)
- Iteradores – map y filter retornan iteradores (lazy), no listas
- Combinación – El poder real surge al combinar estas funciones
- vs Comprensiones – Las comprensiones de lista son más pythónicas para casos simples
- Lambdas – Se combinan perfectamente con estas funciones
Pepitas de conocimiento
- Usa list()para convertir iteradores a listas cuando lo necesites
- filter(None, iterable)elimina valores «falsy» (0, «», None, [], False)
- reduce()necesita- from functools import reduce
- Las comprensiones de lista suelen ser más pythónicas que map/filter
- Usa map/filter/reduce cuando hagas programación funcional explícita
- Los iteradores son más eficientes en memoria que las listas
Próximos pasos
Ahora que dominas las herramientas de programación funcional, es momento de explorar recursión para resolver problemas de forma elegante.
¿Listo para el siguiente nivel?
Descubre cómo escribir funciones recursivas en Python:
Recursión en Python: Guía Completa
¿Te resultó útil esta guía? Compártela con otros desarrolladores Python.
Para patrones avanzados de programación funcional, generadores, decoradores y más, consulta Python a fondo.

 
		 
		 
		