La función reduce() es una de esas funciones que hacen cosas extraordinarias, sin embargo a muchos programadores le ha costado un poco entenderla (me incluyo en los muchos…). Una vez me sumergí en el mundo de ReactJS, entendí que sí no profundizaba en la compresión de este tipo de funciones (map, filter, reduce), no lograría escribir código más limpio y de calidad.
Vamos a ver algunos ejemplos que nos permitan ir un poco mas allá de una definición. En la documentación de mozilla la función reduce() es definida de la siguiente manera:
El método reduce() aplica una función a un acumulador y a cada valor de una array (de izquierda a derecha) para reducirlo a un único valor.
Más claro imposible, con esto terminamos el escrito y estoy seguro ya te sentirás un maestro usando la función reduce(). Bueno, en realidad la primera vez que leí este concepto no lo entendí. Soy honesto, quizás mi coeficiente intelectual no esta la altura, pero en fin, mis felicitaciones a todos aquellos que con solo leerlo ya saben que hacer.
Para todos aquellos que se identifican conmigo vamos a ver unos ejemplos que nos permitan entender más a fondo como emplear esta función. El primero de ellos el más clásico de los ejemplo:
Lo que intentamos hacer es sumar todos los elementos de una array y retornar el total de la suma. Podemos observar que el método reduce(), puede ser implementado directamente al array, luego dentro del array voy a invocar a una función que se encargara de procesar la tarea a realizar.
La función utilizada dentro de reduce es el equivalente en ES6 de:
const suma = [10, 20, 30].reduce(function(a, b){return a + b});
(a, b) son los parámetros que recibe la función, es nuestro ejemplo a = 10 y b = 20. Nuestra función retorna la suma de ambos, es decir 30. Debido a que existen más elementos en el array, la función reduce() es invocada nuevamente, la diferencia radica en que el parámetro “a” ahora es igual a 30 (representa el monto acumulado) y “b” es el elemento restante en el array, es decir 30. Al concretarse la operación el resultado que será mostrado en consola es ahora igual a 60.
En el ejemplo siguiente voy a mostrar como podemos contar la cantidad de nombres repetidos en un aula de clase.
En el código anterior tenemos un array de nombres. Para lograr contarlos, llamo a la función reduce() y dentro de ella paso una función como parámetro que a su vez recibirá sus propios parámetros (contadorNombre, nombre), nombre representa cada elemento del array y contadorNombre será una objeto donde guardaré la cantidad de veces que un nombre se repita. A diferencia del ejemplo anterior donde retornábamos un array, aquí el resultado será un objeto, por lo tanto a la función reduce, debo pasarle un parámetro más, que en este caso es un objeto vacío y representa el estado inicial de mi contador de nombres.
Cuando la función se ejecuta, seria algo como esto:
// Primera ejecución
1.- contadorNombre = {} // Objecto vacío
2.- nombre = Jorge // Primer elemento del array
3.- {Jorge: 1}
4.- Se retorna el objecto existen -> {Jorge: 1}
5.- contadorNombre = {Jorge: 1} // Se repite el ciclo
En un ultimo ejemplo vamos a usar lo que se conoce como las pipe functions, donde básicamente lo que se hace es llamar a una función, retornar una valor y pasarlo nuevamente a otra función, algo así como encadenar varias funciones a la vez.
Los primero que hago es definir tres funciones básicas que me permiten hacer operaciones matemáticas (sumar y multiplicar). Luego, defino una función que recibe dos funciones como parámetros las cuales son pasadas a una nueva función. Los funciones son pasadas como argumentos usando el operador spread de ES6 y son invocadas una dentro de la otra.
const _pipe = (f, g) => (...args) => g(f(...args));
const ejemplo = _pipe(suma, dobla);
const resultadoEjemplo = ejemplo(3);
console.log(resultadoEjemplo); // 8
- Paso las funciones suma y doble a la función _pipe(),
- Luego estas serán pasadas una a una y luego invocadas.
- Primero se invoca suma y retornará 3 + 1 = 4
- El valor de 4 será pasado a la siguiente función, en nuestro caso dobla()
- El resultado será 4 * 2 = 8
Esto funciona muy bien para dos funciones, pero mi objetivo es aplicar el mismo procedimiento a multiple funciones. Aquí es donde la función reduce() es útil. En la imagen de arriba, podemos ver que en la línea 6 contamos con el siguiente código:
const pipe = (...fns) => fns.reduce(_pipe);
Con esto nos aseguramos que podemos pasar cualquier cantidad de funciones (…fns), las cuales serán ejecutadas dentro de _pipe() y su valor será retornado y posteriormente pasado a la siguiente función en la lista de argumentos en (…fns). Con esto logramos la meta ya que si creamos lo siguiente función:
const funcionesMixtas = pipe(dobla, suma, triplica);
Y posteriormente la invocamos con un número cualquiera:
const resultado = funcionesMixtas(3)
Lo que sucederá es que primero, se invocará a la función dobla (3 * 2 = 6). Se pasará el valor a la siguiente función, en nuestro ejemplo es suma (6 + 1) y por ultimo se invocará a la tercera función que se encargara de triplicar el resultado (7 * 3 = 21).
Conclusión
La función reduce() permite lograr objetivos que generalmente de manera estructurada cuestan un poco de trabajo lograr. El dominio de este tipo de funciones nos permitirán logra una código más limpio y mucho más fácil de leer. Es cierto que a veces vemos ejemplos que por su complejidad parecen muy difíciles de replicar o aprender, en todo caso te invito a seguir practicando y poco a poco te aseguro que lograrás comprender hasta el mas complejo de los ejemplos, después de todo como dicen por allí, la práctica hace al maestro.