Inspirado por escribir esta respuesta, terminé expandiéndome más tarde y escribiendo una publicación de blog que repasa esto en detalle. Recomiendo verificar eso si desea desarrollar una comprensión más profunda de cómo pensar sobre este problema; trato de explicarlo pieza por pieza y también doy una comparación JSperf al final, repasando las consideraciones de velocidad.
Dicho esto, el tl; dr es esto: para lograr lo que está pidiendo (filtrado y mapeo dentro de una llamada de función), usaríaArray.reduce()
.
Sin embargo, el enfoque más legible y (menos importante) generalmente significativamente más rápido 2 es usar el filtro y el mapa encadenados juntos:
[1,2,3].filter(num => num > 2).map(num => num * 2)
Lo que sigue es una descripción de cómo Array.reduce()
funciona y cómo se puede utilizar para realizar el filtrado y el mapa en una iteración. Nuevamente, si esto está demasiado condensado, recomiendo ver la publicación del blog vinculada arriba, que es una introducción mucho más amigable con ejemplos claros y progresión.
Le da a reduce un argumento que es una función (generalmente anónima).
Esa función anónima toma dos parámetros: uno (como las funciones anónimas pasadas a map / filter / forEach) es el iteratee sobre el que se operará. Hay otro argumento para que la función anónima pasada reduzca, sin embargo, que esas funciones no aceptan, y ese es el valor que se pasará entre llamadas a funciones, a menudo denominado memo .
Tenga en cuenta que mientras Array.filter () toma solo un argumento (una función), Array.reduce () también toma un segundo argumento importante (aunque opcional): un valor inicial para 'memo' que se pasará a esa función anónima como su primer argumento, y posteriormente se puede mutar y pasar entre llamadas a funciones. (Si no se proporciona, entonces 'memo' en la primera llamada de función anónima será por defecto el primer iteratee, y el argumento 'iteratee' será en realidad el segundo valor en la matriz)
En nuestro caso, pasaremos una matriz vacía para comenzar y luego elegiremos si inyectamos nuestro iteratee en nuestra matriz o no según nuestra función; este es el proceso de filtrado.
Finalmente, devolveremos nuestra 'matriz en progreso' en cada llamada de función anónima, y reduce tomará ese valor de retorno y lo pasará como un argumento (llamado memo) a su próxima llamada de función.
Esto permite que el filtro y el mapa sucedan en una iteración, reduciendo nuestro número de iteraciones requeridas a la mitad; sin embargo, solo hacemos el doble de trabajo en cada iteración, por lo que no se guarda nada más que las llamadas a funciones, que no son tan costosas en javascript. .
Para obtener una explicación más completa, consulte los documentos de MDN (o mi publicación mencionada al principio de esta respuesta).
Ejemplo básico de una llamada Reducir:
let array = [1,2,3];
const initialMemo = [];
array = array.reduce((memo, iteratee) => {
if (iteratee > 1) {
memo.push(iteratee * 2);
}
return memo;
}, initialMemo)
console.log(array)
versión más sucinta:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Observe que el primer iteratee no era mayor que uno, por lo que se filtró. También tenga en cuenta el InitialMemo, nombrado solo para aclarar su existencia y llamar la atención sobre él. Una vez más, se pasa como 'memo' a la primera llamada de función anónima, y luego el valor devuelto de la función anónima se pasa como el argumento 'memo' a la siguiente función.
Otro ejemplo del caso de uso clásico de memo sería devolver el número más pequeño o más grande en una matriz. Ejemplo:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
Un ejemplo de cómo escribir su propia función de reducción (esto a menudo ayuda a comprender funciones como estas, encuentro):
test_arr = [];
test_arr.my_reducer = function(reduceFunc, initialMemo) {
const initialMemoIsIndexZero = arguments.length < 2;
let memo = initialMemoIsIndexZero ? this[0] : initialMemo;
const initialIteratee = initialMemoIsIndexZero ? 1 : 0;
for (var i = initialIteratee; i < this.length; i++) {
memo = reduceFunc(memo, this[i]);
}
return memo;
}
La implementación real permite el acceso a cosas como el índice, por ejemplo, pero espero que esto te ayude a tener una idea sencilla de lo esencial.