CAP 08 · LEC 02·Colecciones avanzadas

map, filter, reduce y functools: transformar datos funcionalmente

map, filter y reduce son las herramientas clásicas de programación funcional. Python las incluye, aunque a menudo las comprehensions son más Pythonicas. Conocerlas es esencial para entender código legado y librerías.

● INTERMEDIO9 min lectura5 ejerciciospor Fernando Herrera · actualizado mayo de 2026
¿Encontraste un error o algo que mejorar?Editá esta lección en GitHub →

map() con funciones y lambda

map(función, iterable) aplica una función a cada elemento de un iterable y devuelve un iterador lazy. Debes convertirlo a lista si quieres verlo completo.

# map con una función nombrada def al_cuadrado(n): return n ** 2 numeros = [1, 2, 3, 4, 5] resultado = list(map(al_cuadrado, numeros)) print(resultado) # [1, 4, 9, 16, 25] # map con lambda (función anónima en línea) dobles = list(map(lambda x: x * 2, numeros)) print(dobles) # [2, 4, 6, 8, 10] # map sobre strings nombres = ["ana", "carlos", "beatriz"] mayusculas = list(map(str.upper, nombres)) print(mayusculas) # ['ANA', 'CARLOS', 'BEATRIZ'] # map con múltiples iterables a = [1, 2, 3] b = [10, 20, 30] sumas = list(map(lambda x, y: x + y, a, b)) print(sumas) # [11, 22, 33]
Salida[1, 4, 9, 16, 25] [2, 4, 6, 8, 10] ['ANA', 'CARLOS', 'BEATRIZ'] [11, 22, 33]
map() devuelve un iterador, no una lista

map() es lazy: no evalúa nada hasta que iteras. Envuelve con list() cuando necesitas el resultado completo, o itera directamente en un for loop para ahorrar memoria.

filter() para subconjuntos

filter(función, iterable) devuelve un iterador con los elementos para los que la función retorna True. Si pasas None como función, filtra los valores falsy.

# Filtrar números pares numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] pares = list(filter(lambda n: n % 2 == 0, numeros)) print(pares) # [2, 4, 6, 8, 10] # Filtrar strings no vacíos datos = ["python", "", "es", None, "genial", ""] # filter con None elimina los valores falsy validos = list(filter(None, datos)) print(validos) # ['python', 'es', 'genial'] # Filtrar objetos por atributo usuarios = [ {"nombre": "Ana", "activo": True}, {"nombre": "Bob", "activo": False}, {"nombre": "Carlos", "activo": True}, ] activos = list(filter(lambda u: u["activo"], usuarios)) print([u["nombre"] for u in activos]) # ['Ana', 'Carlos']
Salida[2, 4, 6, 8, 10] ['python', 'es', 'genial'] ['Ana', 'Carlos']

functools.reduce() para acumulación

reduce(función, iterable) aplica una función acumulativa de izquierda a derecha, reduciendo el iterable a un solo valor. En Python 3 está en functools.

from functools import reduce # Sumar todos los elementos numeros = [1, 2, 3, 4, 5] total = reduce(lambda acc, n: acc + n, numeros) print(total) # 15 # Producto de todos los elementos producto = reduce(lambda acc, n: acc * n, numeros) print(producto) # 120 # Encontrar el máximo manualmente maximo = reduce(lambda a, b: a if a > b else b, numeros) print(maximo) # 5 # Con valor inicial (segundo parámetro de reduce) suma_con_base = reduce(lambda acc, n: acc + n, numeros, 100) print(suma_con_base) # 115 (100 + 1 + 2 + 3 + 4 + 5)
Salida15 120 5 115
reduce vs sum/max/min

Para operaciones comunes como suma, máximo o mínimo, Python ya tiene sum(), max() y min(). Usa reduce() solo cuando necesitas una operación de acumulación personalizada que no tiene built-in equivalente.

Comparación: comprehension vs map/filter

En Python moderno, las comprehensions suelen ser más legibles que map/filter. Conoce ambas formas — el código legado usa mucho map/filter.

map / filterList comprehension
list(map(lambda x: x**2, nums))[x**2 for x in nums]
list(filter(lambda x: x>0, nums))[x for x in nums if x>0]
list(map(f, filter(g, nums)))[f(x) for x in nums if g(x)]
numeros = [-3, -1, 0, 2, 4, 7] # Opción A: map + filter anidados (menos legible) resultado_a = list(map(lambda n: n ** 2, filter(lambda n: n > 0, numeros))) # Opción B: list comprehension (más legible) resultado_b = [n ** 2 for n in numeros if n > 0] print(resultado_a) # [4, 16, 49] print(resultado_b) # [4, 16, 49] print(resultado_a == resultado_b) # True
Salida[4, 16, 49] [4, 16, 49] True

functools.partial y functools.lru_cache

functools tiene más herramientas útiles: partial para fijar argumentos y lru_cache para memorizar resultados de funciones puras costosas.

from functools import partial, lru_cache # partial: crea una función con argumentos pre-rellenados def potencia(base, exponente): return base ** exponente al_cuadrado = partial(potencia, exponente=2) al_cubo = partial(potencia, exponente=3) print(al_cuadrado(5)) # 25 print(al_cubo(3)) # 27 # Útil con map para evitar lambdas complejas numeros = [1, 2, 3, 4, 5] print(list(map(al_cuadrado, numeros))) # [1, 4, 9, 16, 25] # lru_cache: memoiza una función (guarda resultados ya calculados) @lru_cache(maxsize=None) def fibonacci(n: int) -> int: if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) print(fibonacci(35)) # 9227465 — rápido gracias al caché print(fibonacci.cache_info()) # CacheInfo(hits=33, misses=36, ...)
Salida25 27 [1, 4, 9, 16, 25] 9227465 CacheInfo(hits=33, misses=36, maxsize=None, currsize=36)

Practica