Saltar al contenido
Editor

map(), filter() y reduce() en Python: funciones de orden superior

Intermedio25 min7 ejercicios100 XP

Esta lección es una traducción del original en inglés.Read in EnglishAvisar de un error de traducción

0/7 ejercicios

Imagina una cadena de montaje en una fábrica. Las materias primas entran por un extremo. En la primera estación se da forma a cada pieza. En la siguiente se retiran las piezas defectuosas. En la estación final, todas las piezas buenas se combinan en un único producto terminado.

Python tiene tres funciones que trabajan exactamente como esta cadena de montaje: map() transforma cada elemento, filter() se queda solo con los elementos que quieres y reduce() lo combina todo en un único resultado. Juntas, te permiten procesar colecciones de datos de forma limpia y legible.

En este tutorial aprenderás cómo funcionan estas herramientas, cuándo usarlas y cuándo una comprensión de listas (list comprehension) puede ser mejor opción. Al terminar, escribirás pipelines de datos que harían sentir orgulloso a cualquier jefe de fábrica.

¿Qué son las funciones de orden superior?

Una función de orden superior es una función que recibe otra función como argumento o que devuelve una función como resultado. Eso es todo.

Ya has usado una sin darte cuenta. La función integrada sorted() tiene un parámetro key al que le pasas una función:

sorted() es una función de orden superior
words = ["banana", "apple", "cherry"]
# sorted() is a higher-order function
# It takes len as an argument - a function!
sorted_words = sorted(words, key=len)
print(sorted_words)
Salida
['apple', 'banana', 'cherry']

Aquí, len se pasa como argumento a sorted(). La función sorted llama a len con cada elemento para decidir el orden. Tú no llamaste a len(): solo le dijiste a sorted qué función usar.

map(), filter() y reduce() funcionan todas así. Les das una función y una colección, y ellas aplican esa función a los elementos. Eso es lo que las convierte en funciones de orden superior.

map(): transforma cada elemento

map() recibe una función y un iterable (como una lista), aplica la función a cada elemento y devuelve los resultados transformados. Piensa en ella como la "estación de moldeado" de nuestra cadena de montaje.

La sintaxis es: map(function, iterable). Devuelve un objeto map, que normalmente conviertes en lista.

Usar map() para duplicar cada número
numbers = [1, 2, 3, 4, 5]
# Double every number
def double(x):
return x * 2
result = list(map(double, numbers))
print(result)
Salida
[2, 4, 6, 8, 10]

map(double, numbers) llama a double(1), double(2), double(3), etc., y reúne todos los resultados. La llamada a list() que lo envuelve convierte el objeto map en una lista normal para que podamos imprimirla.

Como escribir una función entera solo para duplicar un número resulta pesado, map() se suele combinar con una lambda, una función anónima diminuta:

map() con lambda y con funciones integradas
numbers = [1, 2, 3, 4, 5]
# Same thing, but with a lambda
result = list(map(lambda x: x * 2, numbers))
print(result)
# More examples
names = ["alice", "bob", "charlie"]
print(list(map(str.upper, names)))
prices = [10.5, 20.3, 5.99]
print(list(map(round, prices)))
Salida
[2, 4, 6, 8, 10]
['ALICE', 'BOB', 'CHARLIE']
[10, 20, 6]

Puedes pasar cualquier función a map(): tus propias funciones, lambdas o funciones integradas como str.upper, round, len o int.

filter(): quédate solo con lo que necesitas

filter() recibe una función y un iterable. La función debe devolver True o False para cada elemento. Solo se conservan los elementos para los que la función devuelve True. Piensa en ella como el control de calidad de la cadena de montaje: se retiran las piezas defectuosas.

Usar filter() para quedarse con los números pares
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Keep only even numbers
def is_even(x):
return x % 2 == 0
result = list(filter(is_even, numbers))
print(result)
Salida
[2, 4, 6, 8, 10]

filter(is_even, numbers) llama a is_even(1), que devuelve False (así que el 1 se descarta), a is_even(2), que devuelve True (así que el 2 se conserva), y así sucesivamente. Solo sobreviven los elementos que pasan la prueba.

Más ejemplos de filter()
words = ["hello", "", "world", "", "python", ""]
# Remove empty strings - filter with bool
result = list(filter(bool, words))
print(result)
# Keep words longer than 4 characters
long_words = list(filter(lambda w: len(w) > 4, words))
print(long_words)
# Keep positive numbers
numbers = [-3, -1, 0, 2, 5, -4, 8]
positives = list(filter(lambda x: x > 0, numbers))
print(positives)
Salida
['hello', 'world', 'python']
['hello', 'world', 'python']
[2, 5, 8]

Pasar bool a filter() es un truco muy práctico. Las cadenas vacías, el cero, None y las listas vacías son valores "falsy" en Python (se evalúan como falsos): bool() devuelve False para ellos. Así que filter(bool, items) elimina todos los valores falsy.

Combinar map() y filter()

La verdadera potencia aparece al encadenarlas. Primero filtras para seleccionar elementos y luego aplicas map para transformarlos, igual que las estaciones de una cadena de montaje.

Encadenar filter() y map()
scores = [45, 82, 91, 67, 55, 38, 73, 88, 95, 60]
# Step 1: Filter passing scores (>= 60)
passing = filter(lambda s: s >= 60, scores)
# Step 2: Add 5 bonus points to each passing score
boosted = map(lambda s: s + 5, passing)
# Convert to list and print
result = list(boosted)
print(result)
Salida
[87, 96, 72, 78, 93, 100, 65]

Como tanto filter() como map() son perezosas, puedes encadenarlas sin crear listas intermedias. Los datos fluyen por el pipeline de forma eficiente.

Aquí tienes un ejemplo más práctico, que procesa una lista de precios de productos:

Pipeline práctico: filtrar y luego transformar
prices = [12.99, 5.50, 89.99, 3.25, 45.00, 2.99, 150.00]
# Keep prices over $10, then apply 20% discount
result = list(
map(
lambda p: round(p * 0.8, 2),
filter(lambda p: p > 10, prices)
)
)
print(result)
Salida
[10.39, 71.99, 36.0, 120.0]

reduce(): combina todos los elementos en uno

reduce() recibe una función y un iterable, y combina todos los elementos en un único valor. Es la estación final de la cadena de montaje: todas las piezas se ensamblan en un solo producto.

A diferencia de map() y filter(), reduce() no es una función integrada. Tienes que importarla del módulo functools.

Usar reduce() para combinar valores
from functools import reduce
numbers = [1, 2, 3, 4, 5]
# Sum all numbers: ((((1+2)+3)+4)+5) = 15
total = reduce(lambda a, b: a + b, numbers)
print(f"Sum: {total}")
# Multiply all numbers: ((((1*2)*3)*4)*5) = 120
product = reduce(lambda a, b: a * b, numbers)
print(f"Product: {product}")
Salida
Sum: 15
Product: 120

Así funciona reduce() paso a paso en la suma. La función recibe dos argumentos: el resultado acumulado hasta el momento (a) y el siguiente elemento (b):

  • Empieza con los dos primeros elementos: a=1, b=2 da 3
  • Toma ese resultado y el siguiente elemento: a=3, b=3 da 6
  • Continúa: a=6, b=4 da 10
  • Por último: a=10, b=5 da 15
  • Más ejemplos de reduce()
    from functools import reduce
    # Find the longest word
    words = ["cat", "elephant", "dog", "hippopotamus"]
    longest = reduce(lambda a, b: a if len(a) >= len(b) else b, words)
    print(f"Longest word: {longest}")
    # Join words with a separator
    result = reduce(lambda a, b: f"{a} & {b}", ["Alice", "Bob", "Charlie"])
    print(result)
    Salida
    Longest word: hippopotamus
    Alice & Bob & Charlie

    map/filter frente a comprensiones de listas

    Python ofrece otra forma de transformar y filtrar listas: las comprensiones de listas. A menudo dan un código más legible que map() y filter(). Comparemos.

    Con map() y filter()
    numbers = [1, 2, 3, 4, 5, 6]
    
    # Double even numbers
    evens = filter(lambda x: x % 2 == 0, numbers)
    result = list(map(lambda x: x * 2, evens))
    print(result)  # [4, 8, 12]
    Con una comprensión de listas
    numbers = [1, 2, 3, 4, 5, 6]
    
    # Double even numbers
    result = [x * 2 for x in numbers if x % 2 == 0]
    print(result)  # [4, 8, 12]

    La comprensión de listas filtra y transforma en una sola línea fácil de leer. Para transformaciones sencillas, las comprensiones suelen ser la mejor opción en Python.

    Entonces, ¿cuándo conviene usar map() y filter()? Son útiles cuando ya tienes una función con nombre que aplicar:

    map() brilla con funciones con nombre
    # When you have a named function, map() reads nicely
    names = ["alice", "bob", "charlie"]
    print(list(map(str.capitalize, names)))
    # Equivalent comprehension - a bit more verbose
    print([name.capitalize() for name in names])
    Salida
    ['Alice', 'Bob', 'Charlie']
    ['Alice', 'Bob', 'Charlie']

    Ejercicios de práctica

    Es hora de practicar. Estos ejercicios empiezan con funciones sueltas y avanzan hasta combinarlas en pipelines. Recuerda envolver map() y filter() en list() al imprimir.

    Ejercicio 1: eleva al cuadrado cada número
    Escribe el código

    Usa map() con una lambda para elevar al cuadrado cada número de la lista [1, 2, 3, 4, 5].

    Imprime el resultado como lista.

    Salida esperada:

    [1, 4, 9, 16, 25]
    numbers = [1, 2, 3, 4, 5]
    # Use map() to square each number
    Ejercicio 2: descarta las palabras cortas
    Escribe el código

    Usa filter() con una lambda para quedarte solo con las palabras que tienen más de 3 caracteres.

    Datos: ["hi", "hello", "hey", "world", "ok", "python"]

    Imprime el resultado como lista.

    Salida esperada:

    ['hello', 'world', 'python']
    words = ["hi", "hello", "hey", "world", "ok", "python"]
    # Use filter() to keep words longer than 3 characters
    Ejercicio 3: predice la salida del pipeline
    Predice la salida

    Lee este código y predice la salida. Después escribe una instrucción print() que produzca exactamente la misma salida.

    numbers = [10, 25, 30, 45, 50]
    result = list(map(lambda x: x // 10, filter(lambda x: x >= 30, numbers)))
    print(result)

    Piensa paso a paso: ¿qué conserva filter y qué hace después map con cada elemento?

    # Print the exact output
    Ejercicio 4: arregla el pipeline roto
    Corrige el error

    Este código debería convertir una lista de temperaturas en texto, como ["32F", "100F", "212F"], en enteros en grados Celsius. Pero tiene dos errores.

    Salida esperada:

    [0, 38, 100]

    Fórmula: Celsius = (Fahrenheit - 32) * 5 / 9, y luego se redondea al entero más cercano.

    temps = ["32F", "100F", "212F"]
    # Bug 1: Need to extract the number from the string
    # Bug 2: Formula or conversion issue
    result = list(map(lambda t: round((t - 32) * 5 / 9), temps))
    print(result)
    Ejercicio 5: calcula el producto con reduce()
    Escribe el código

    Usa reduce() del módulo functools para calcular el producto de todos los números de la lista [2, 3, 4, 5].

    El producto es 2 * 3 * 4 * 5 = 120.

    Imprime el resultado.

    Salida esperada:

    120
    from functools import reduce
    numbers = [2, 3, 4, 5]
    # Use reduce() to multiply all numbers together
    Ejercicio 6: construye un pipeline de datos
    Escribe el código

    Dada una lista de calificaciones de estudiantes, construye un pipeline que:

    1. Descarte las calificaciones que no aprueban (conserva solo las calificaciones >= 60)

    2. Suba cada calificación aprobada sumándole 10 (usa map)

    3. Limite las calificaciones a un máximo de 100 (usa map con min)

    Datos: [45, 82, 55, 91, 67, 38, 73, 95]

    Imprime la lista final.

    Salida esperada:

    [92, 100, 77, 83, 100]

    Pista: para limitar a 100, usa min(score, 100).

    scores = [45, 82, 55, 91, 67, 38, 73, 95]
    # Step 1: Filter passing scores (>= 60)
    # Step 2: Add 10 bonus points
    # Step 3: Cap at 100
    Ejercicio 7: refactoriza con una comprensión de listas
    Mejora el código

    Reescribe este pipeline de map/filter como una sola comprensión de listas que produzca la misma salida.

    Código original:

    words = ["Hello", "WORLD", "Python", "CODE", "test"]
    result = list(map(str.lower, filter(lambda w: len(w) > 4, words)))

    Escribe una comprensión de listas que produzca el mismo resultado e imprímelo.

    Salida esperada:

    ['hello', 'world', 'python']
    words = ["Hello", "WORLD", "Python", "CODE", "test"]
    # Refactor to a list comprehension
    result = [] # Replace with your comprehension
    print(result)

    Resumen

    Lo que ya sabes sobre las herramientas funcionales de Python:

    FunciónPara qué sirveDevuelve
    map(fn, iterable)Transforma cada elementoObjeto map (perezoso)
    filter(fn, iterable)Conserva los elementos para los que fn devuelve TrueObjeto filter (perezoso)
    reduce(fn, iterable)Combina todos los elementos en un solo valorUn único valor
    Función de orden superiorUna función que recibe o devuelve una funciónDepende de la función

    La conclusión práctica: usa comprensiones de listas para la mayoría de las tareas de transformar o filtrar en Python. Recurre a map() y filter() cuando tengas una función con nombre que aplicar o necesites evaluación perezosa. Usa reduce() con moderación: las funciones integradas de Python resuelven mejor la mayoría de los casos.

    ¿Qué sigue?

    Ya tienes una base sólida en funciones de Python. Ahora explora el [manejo de errores](/python/python-try-except) para aprender a escribir código que gestione los fallos con elegancia en lugar de detenerse con un error.

    Tutoriales relacionados

    ¿Te sirvió este tutorial?

    Sugerir una mejora