Me gustaría filtrar una matriz de elementos usando la map()
función. Aquí hay un fragmento de código:
var filteredItems = items.map(function(item)
{
if( ...some condition... )
{
return item;
}
});
El problema es que los elementos filtrados todavía usan espacio en la matriz y me gustaría eliminarlos por completo.
¿Alguna idea?
EDITAR: Gracias, me olvidé filter()
, lo que quería es en realidad un filter()
entonces a map()
.
EDIT2: Gracias por señalar eso map()
y filter()
no están implementados en todos los navegadores, aunque mi código específico no estaba destinado a ejecutarse en un navegador.
javascript
functional-programming
data-manipulation
client-side
Vincent Robert
fuente
fuente
Respuestas:
Debería utilizar el
filter
método en lugar del mapa a menos que desee mutar los elementos de la matriz, además de filtrar.p.ej.
var filteredItems = items.filter(function(item) { return ...some condition...; });
[Editar: por supuesto que siempre puedes
sourceArray.filter(...).map(...)
filtrar y mutar]fuente
map
no mutamap
.x=[1,2,3];y = x.map(z => z*2);console.log(x,y);
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ía
Array.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 condition is our filter if (iteratee > 1) { // what happens inside the filter is the map memo.push(iteratee * 2); } // this return value will be passed in as the 'memo' argument // to the next call of this function, and this function will have // every element passed into it at some point. return memo; }, initialMemo) console.log(array) // [4,6], equivalent to [(2 * 2), (3 * 2)]
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) // ^this would return the largest number in the list.
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 = []; // we accept an anonymous function, and an optional 'initial memo' value. test_arr.my_reducer = function(reduceFunc, initialMemo) { // if we did not pass in a second argument, then our first memo value // will be whatever is in index zero. (Otherwise, it will // be that second argument.) const initialMemoIsIndexZero = arguments.length < 2; // here we use that logic to set the memo value accordingly. let memo = initialMemoIsIndexZero ? this[0] : initialMemo; // here we use that same boolean to decide whether the first // value we pass in as iteratee is either the first or second // element const initialIteratee = initialMemoIsIndexZero ? 1 : 0; for (var i = initialIteratee; i < this.length; i++) { // memo is either the argument passed in above, or the // first item in the list. initialIteratee is either the // first item in the list, or the second item in the list. memo = reduceFunc(memo, this[i]); // or, more technically complete, give access to base array // and index to the reducer as well: // memo = reduceFunc(memo, this[i], i, this); } // after we've compressed the array into a single value, // we return it. 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.
fuente
reduce
es que, a diferencia defilter
+map
, a la devolución de llamada se le puede pasar un argumento de índice que es el índice de la matriz original, y no el de la filtrada.Eso no es lo que hace el mapa. Realmente quieres Array.filter . O si realmente desea eliminar los elementos de la lista original, tendrá que hacerlo imperativamente con un bucle for.
fuente
Método de filtro de matriz
var arr = [1, 2, 3] // ES5 syntax arr = arr.filter(function(item){ return item != 3 }) // ES2015 syntax arr = arr.filter(item => item != 3) console.log( arr )
fuente
var arr = [1,2,"xxx", "yyy"]; arr = arr.filter(function(e){ return e!="xxx" }) console.log(arr)
Sin embargo, debe tener en cuenta que
Array.filter
no es compatible con todos los navegadores, por lo que debe crear un prototipo://This prototype is provided by the Mozilla foundation and //is distributed under the MIT license. //http://www.ibiblio.org/pub/Linux/LICENSES/mit.license if (!Array.prototype.filter) { Array.prototype.filter = function(fun /*, thisp*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); var res = new Array(); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { var val = this[i]; // in case fun mutates this if (fun.call(thisp, val, i, this)) res.push(val); } } return res; }; }
Y al hacerlo, puede crear un prototipo de cualquier método que necesite.
fuente
La siguiente declaración limpia el objeto usando la función de mapa.
var arraytoclean = [{v:65, toberemoved:"gronf"}, {v:12, toberemoved:null}, {v:4}]; arraytoclean.map((x,i)=>x.toberemoved=undefined); console.dir(arraytoclean);
fuente
Acabo de escribir una intersección de matriz que maneja correctamente también los duplicados
https://gist.github.com/gkucmierz/8ee04544fa842411f7553ef66ac2fcf0
// array intersection that correctly handles also duplicates const intersection = (a1, a2) => { const cnt = new Map(); a2.map(el => cnt[el] = el in cnt ? cnt[el] + 1 : 1); return a1.filter(el => el in cnt && 0 < cnt[el]--); }; const l = console.log; l(intersection('1234'.split``, '3456'.split``)); // [ '3', '4' ] l(intersection('12344'.split``, '3456'.split``)); // [ '3', '4' ] l(intersection('1234'.split``, '33456'.split``)); // [ '3', '4' ] l(intersection('12334'.split``, '33456'.split``)); // [ '3', '3', '4' ]
fuente
Primero puede usar el mapa y con el encadenamiento puede usar el filtro
state.map(item => { if(item.id === action.item.id){ return { id : action.item.id, name : item.name, price: item.price, quantity : item.quantity-1 } }else{ return item; } }).filter(item => { if(item.quantity <= 0){ return false; }else{ return true; } });
fuente