Introducción
los map()
, filter()
y reduce()
Las funciones aportan un poco de programación funcional a Python. Las tres son funciones de conveniencia que se pueden reemplazar con listas comprensivas o bucles, pero brindan un enfoque más elegante y abreviado para algunos problemas.
Antes de continuar, repasaremos algunas cosas con las que debería estar familiarizado antes de leer sobre los métodos mencionados anteriormente:
¿Qué es una función / método anónimo o lambda?
Un método anónimo es un método sin nombre, es decir, no vinculado a un identificador como cuando definimos un método usando def method:
.
Nota: Aunque la mayoría de la gente usa los términos «función anónima» y «función lambda» indistintamente, no son lo mismo. Este error ocurre porque en la mayoría de los lenguajes de programación las lambdas son anónimas y todas las funciones anónimas son lambdas. Este también es el caso de Python. Por lo tanto, no profundizaremos en esta distinción en este artículo.
¿Cuál es la sintaxis de una función lambda (u operador lambda)?
lambda arguments: expression
Piense en lambdas como métodos de una línea sin nombre. Funcionan prácticamente igual que cualquier otro método en Python, por ejemplo:
Te puede interesar:Leer y escribir archivos JSON en Python con Pandasdef add(x,y):
return x + y
Puede traducirse a:
lambda x, y: x + y
Las lambdas difieren de los métodos normales de Python porque solo pueden tener una expresión, no pueden contener declaraciones y su tipo de retorno es un function
objeto. Entonces, la línea de código anterior no devuelve exactamente el valor x + y
pero la función que calcula x + y
.
¿Por qué las lambdas son relevantes para map()
, filter()
y reduce()
?
Los tres de estos métodos esperan una function
objeto como primer argumento. Esta function
El objeto puede ser un método predefinido con un nombre (como def add(x,y)
).
Aunque, la mayoría de las veces, las funciones pasan a map()
, filter()
y reduce()
son los que usaría solo una vez, por lo que a menudo no tiene sentido definir una función referenciable.
Para evitar definir una nueva función para sus diferentes map()
/filter()
/reduce()
necesidades: una solución más elegante sería utilizar una función breve, desechable y anónima que solo usará una vez y nunca más: una lambda.
La función map ()
los map()
La función itera a través de todos los elementos en el iterable dado y ejecuta el function
pasamos como argumento en cada uno de ellos.
La sintaxis es:
map(function, iterable(s))
Podemos pasar tantos objetos iterables como queramos después de pasar el function
queremos usar:
# Without using lambdas
def starts_with_A(s):
return s[0] == "A"
fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
map_object = map(starts_with_A, fruit)
print(list(map_object))
Este código resultará en:
[True, False, False, True, False]
Como podemos ver, terminamos con una nueva lista donde la función starts_with_A()
fue evaluado para cada uno de los elementos de la lista fruit
. Los resultados de esta función se agregaron a la lista de forma secuencial.
Una forma más bonita de hacer exactamente lo mismo es usando lambdas:
fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
map_object = map(lambda s: s[0] == "A", fruit)
print(list(map_object))
Obtenemos el mismo resultado:
[True, False, False, True, False]
Nota: Puede que hayas notado que hemos emitido map_object
a una lista para imprimir el valor de cada elemento. Hicimos esto porque llamamos print()
en una lista imprimirá los valores reales de los elementos. Vocación print()
en map_object
imprimiría las direcciones de memoria de los valores en su lugar.
los map()
función devuelve el map_object
type, que es iterable y podríamos haber impreso los resultados de esta manera también:
for value in map_object:
print(value)
Si quieres el map()
función para devolver una lista en su lugar, puede simplemente convertirla al llamar a la función:
result_list = list(map(lambda s: s[0] == "A", fruit))
La función filter ()
Similar a map()
, filter()
toma una function
objeto y un iterable y crea una nueva lista.
Como el nombre sugiere, filter()
forma una nueva lista que contiene solo elementos que satisfacen una determinada condición, es decir, la function
pasamos devoluciones True
.
La sintaxis es:
filter(function, iterable(s))
Usando el ejemplo anterior, podemos ver que la nueva lista solo contendrá elementos para los cuales el starts_with_A()
devuelve la función True
:
# Without using lambdas
def starts_with_A(s):
return s[0] == "A"
fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
filter_object = filter(starts_with_A, fruit)
print(list(filter_object))
Ejecutar este código resultará en una lista más corta:
Te puede interesar:Algoritmo de optimización de búsqueda de cuadrícula en Python['Apple', 'Apricot']
O reescrito usando una lambda:
fruit = ["Apple", "Banana", "Pear", "Apricot", "Orange"]
filter_object = filter(lambda s: s[0] == "A", fruit)
print(list(filter_object))
La impresión nos da el mismo resultado:
['Apple', 'Apricot']
La función reduce ()
reduce()
funciona de manera diferente a map()
y filter()
. No devuelve una nueva lista basada en el function
e iterable hemos pasado. En cambio, devuelve un solo valor.
Además, en Python 3 reduce()
ya no es una función incorporada, y se puede encontrar en el functools
módulo.
La sintaxis es:
reduce(function, sequence[, initial])
reduce()
funciona llamando al function
pasamos por los dos primeros elementos de la secuencia. El resultado devuelto por el function
se usa en otra llamada a function
junto con el siguiente (tercero en este caso), elemento.
Este proceso se repite hasta que hayamos pasado por todos los elementos de la secuencia.
Te puede interesar:Combinar ordenar en PythonEl argumento opcional initial
se utiliza, cuando está presente, al comienzo de este «bucle» con el primer elemento en la primera llamada a function
. En cierto modo, el initial
elemento es el elemento 0, antes del primero, cuando se proporciona.
reduce()
es un poco más difícil de entender que map()
y filter()
, así que veamos un ejemplo paso a paso:
- Empezamos con una lista
[2, 4, 7, 3]
y pasar eladd(x, y)
función parareduce()
junto a esta lista, sin uninitial
valor reduce()
llamadasadd(2, 4)
yadd()
devoluciones6
reduce()
llamadasadd(6, 7)
(resultado de la llamada anterior aadd()
y el siguiente elemento de la lista como parámetros), yadd()
devoluciones13
reduce()
llamadasadd(13, 3)
yadd()
devoluciones16
- Como no quedan más elementos en la secuencia,
reduce()
devoluciones16
La única diferencia, si hubiéramos dado un initial
valor hubiera sido un paso adicional – 1.5. dónde reduce()
Llamaría add(initial, 2)
y usa ese valor de retorno en el paso 2.
Sigamos adelante y usemos el reduce()
función:
from functools import reduce
def add(x, y):
return x + y
list = [2, 4, 7, 3]
print(reduce(add, list))
Ejecutar este código produciría:
16
Nuevamente, esto podría escribirse usando lambdas:
from functools import reduce
list = [2, 4, 7, 3]
print(reduce(lambda x, y: x + y, list))
print("With an initial value: " + str(reduce(lambda x, y: x + y, list, 10)))
Y el código resultaría en:
Te puede interesar:Lectura y escritura de archivos de MS Word en Python a través del módulo Python-Docx16
With an initial value: 26
Conclusión
Como se mencionó anteriormente, estas funciones son funciones de conveniencia. Están ahí para que pueda evitar escribir un código más engorroso, pero evite usar tanto ellos como las expresiones lambda demasiado.
No fuerce estas herramientas porque «puede», ya que a menudo puede generar un código ilegible que es difícil de mantener. Úselos solo cuando esté absolutamente claro lo que está sucediendo tan pronto como observe la función o expresión lambda.
Si te das cuenta de que estás luchando por encajar la lógica necesaria en una map()
función, o una expresión lambda, es mucho mejor escribir un método for-loop / definido un poco más largo y evitar confusiones innecesarias más adelante.