Muy buenas, soy Luis y aquí les traigo otro nuevo post.
Subestimé completamente el poder de Array.prototype.reduce()
cuando estaba aprendiendo JavaScript por primera vez.
No entendí totalmente cómo funcionaba, así que lo descarté como nada más que una forma conveniente de encontrar la suma de los elementos de una matriz.
reduce
, veo su potencial para todo tipo de aplicaciones diferentes.
Para demostrar este potencial, primero usaré reduce
para imitar el comportamiento de los dos métodos de matriz más comunes que utilizo: map
y filter
y luego mostrar cómo se puede utilizar en lugar de bucles for
para limpiar bien el código.
Reducir como mapa
Para los no iniciados, Array.protoype.map()
es un método que puede usar en cualquier matriz para ejecutar el mismo código en cada uno de sus elementos para producir una nueva matriz transformada. Se parece a esto (>>
indica el valor devuelto):
[1, 2, 3].map(num => num + 1) >> [2, 3, 4]
El método .map()
acepta una función de devolución de llamada como su primer parámetro (aquí estoy pasando una función anónima) y pasa cada elemento en la matriz como el primer argumento a esa función de devolución de llamada.
El mismo resultado se puede lograr con reduce
:
[1, 2, 3].reduce((result, num) => [ ...result, num + 1 ], []) >> [2, 3, 4]
Bien, entonces, ¿qué está pasando aquí? El primer parámetro de la función de devolución de llamada pasado a reduce
es el acumulador, el valor finalmente devuelto por reduce
.
Cada vez ejecuta reduce
esta función de devolución de llamada, se devuelve un nuevo acumulador y se pasa a la siguiente función de devolución de llamada, y así sucesivamente hasta que llega al final de la matriz. Th;;
.
El segundo parámetro de la función de devolución de llamada es el elemento real de la matriz. Entonces, lo que estoy haciendo arriba es copiar el acumulador en una nueva matriz y agregar el elemento de la matriz actual en la nueva matriz.
Esta nueva matriz se convierte en el nuevo acumulador que luego se pasa a la función de devolución de llamada.
El método reduce
también es diferente de map
porque acepta un segundo argumento opcional, que se utiliza como valor inicial del acumulador. En mi ejemplo, pasé una matriz vacía.
Reducir como filtro
Array.prototype.filter()
tiene una estructura similar a map
, pero el resultado es muy diferente. La función de devolución de llamada pasó a filter
se utiliza para determinar qué valores aparecen en la nueva matriz devuelta y cuáles no.
Se parece a esto:
[1, 2, 3].filter(num => num > 1) >> [2, 3]
Cuando vuelve la función de devolución de llamada false
, el elemento que se evalúa se omite de la matriz devuelta.
Utilizando reduce
, se parece a esto:
[1, 2, 3].reduce((result, num) => { return num > 1 ? [ ...result, num ] : result }, []) >> [2, 3]
Imité el comportamiento de filter
devolviendo una declaración ternaria. Si num > 1
evalúa a true
, devuelve una nueva matriz con el contenido del acumulador y el valor actual de num
.
Si la expresión se evalúa como false
, devuelve el acumulador como está, omitiendo el valor actual de num
de la matriz devuelta.
El poder de reducir
Ahora que tenemos una mejor idea de cómo usar reduce
para imitar el comportamiento de otros métodos de matriz, quiero demostrar cómo usar reduce
para reemplazar el código algo feo que me encuentro escribiendo a menudo (generalmente al resolver problemas en Code Wars
o Hacker Rank
).
Primero, veamos el escenario. Necesitamos pasar por una matriz y eliminar cualquier duplicado, devolviendo una nueva matriz con solo los valores únicos de la matriz original.
En lugar de buscar en toda la matriz cada valor dentro de esa matriz, podemos crear un objeto que sirva como una biblioteca que podemos usar para buscar instantáneamente un valor y ver si ya ocurrió.
Cuando estaba aprendiendo a codificar por primera vez, escribí esta solución así:
const unique = array => { const lib = {} const result = [] for(let i=0; i < array.length; i++) { if(!lib[array[i]]) { result.push(array[i]) lib[array[i]] = true } } return result }unique([1, 2, 3, 3, 4, 5, 5]) >> [1, 2, 3, 4, 5]
Este código hace el trabajo, pero no se ve muy bien. Veamos cómo podemos limpiarlo con reduce
:
const unique = array => { return array.reduce( (result, num) => { if(!result.lib[num]) { return { lib: { ...result.lib, [num]: true }, arr: [ ...result.arr, num ] } } else { return result } }, { lib: {}, arr: [] } ).arr } unique([1, 2, 3, 3, 4, 5, 5]) >> [1, 2, 3, 4, 5]
Bien, tal vez el resultado no se vea muy limpio, pero creo que este ejemplo ilustra el vasto potencial de reduce
porque muestra que el acumulador puede ser tan complejo como lo necesite.
Puede almacenar cualquier información que necesite en el acumulador. Solo recuerda devolver siempre un valor, de lo contrario undefined
reemplazará su acumulador y podría causar una confusión frustrante.
¿Disfrutaste este artículo? Si es así, coméntalo.
Añadir comentario