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

Map filter reduce Python - Pipeline transformación datos ilustración

¿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.

Map filter reduce patron en python

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 funcion para cambiar datos en python

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).

Filter funcion en python

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.

Función reduce en python

Importante: reduce() está en el módulo functools, debes importarla:

from functools import reduce

Sintaxis

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)  # 15

Ejemplos 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)  # 1

Reduce 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.

Ver el libro


Combinando map, filter y reduce

El verdadero poder emerge cuando combinas estas funciones:

Pipeline de map, filter reduce en python

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.08

Encadenar 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)  # 220

map(), 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" -> 1

Casos 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:

  1. map() – Transforma cada elemento aplicando una función
  2. filter() – Filtra elementos basándose en una condición booleana
  3. reduce() – Reduce todos los elementos a un solo valor acumulativo (importar de functools)
  4. Iteradores – map y filter retornan iteradores (lazy), no listas
  5. Combinación – El poder real surge al combinar estas funciones
  6. vs Comprensiones – Las comprensiones de lista son más pythónicas para casos simples
  7. 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.

Compartir

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Información básica sobre protección de datos Ver más

  • Responsable: Oscar Ramirez.
  • Finalidad:  Moderar los comentarios.
  • Legitimación:  Por consentimiento del interesado.
  • Destinatarios y encargados de tratamiento: No se ceden o comunican datos a terceros para prestar este servicio. El Titular ha contratado los servicios de alojamiento web a ionos (1&1) que actúa como encargado de tratamiento.
  • Derechos: Acceder, rectificar y suprimir los datos.
  • Información Adicional: Puede consultar la información detallada en la Política de Privacidad.

Publicar un comentario

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para fines de afiliación y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Contiene enlaces a sitios web de terceros con políticas de privacidad ajenas que podrás aceptar o no cuando accedas a ellos. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Ver Política de cookies
Privacidad