¿Cómo saltar un elemento en .map ()?

¿Cómo puedo omitir un elemento de matriz en .map ?

Mi código:

 var sources = images.map(function (img) { if(img.src.split('.').pop() === "json"){ // if extension is .json return null; // skip } else{ return img.src; } }); 

Esto volverá:

 ["img.png", null, "img.png"] 

8 Solutions collect form web for “¿Cómo saltar un elemento en .map ()?”

Sólo .filter() primero:

 var sources = images.filter(function(img) { if (img.src.split('.').pop() === "json") { return false; // skip } return true; }).map(function(img) { return img.src; }); 

Si no quieres hacer eso, lo que no es irrazonable ya que tiene algún costo, puedes usar el .reduce() más general. Generalmente puedes express .map() en términos de .reduce :

 someArray.map(function(element) { return transform(element); }); 

Se puede escribir como

 someArray.reduce(function(result, element) { result.push(transform(element)); return result; }, []); 

Entonces, si necesita omitir elementos, puede hacerlo fácilmente con .reduce() :

 var sources = images.reduce(function(result, img) { if (img.src.split('.').pop() !== "json") { result.push(img.src); } return result; }, []); 

En esa versión, el código en el .filter() de la primera muestra es parte de la callback .reduce() . La fuente de la imagen solo se inserta en la matriz de resultados en el caso donde la operación de filtro la hubiera mantenido.

Actualización: todo lo que pensé que sabía acerca de esta respuesta estaba mal

No deberíamos requerir boost el encadenamiento de puntos y operar en la matriz [].map(fn1).filter(f2)... ya que este enfoque crea matrices intermedias en la memoria en cada función de reducing .

El mejor enfoque funciona con la función de reducción real, por lo que solo hay un paso de datos y no hay matrices adicionales.

La función de reducción es la función que se pasa a reduce y toma un acumulador y la entrada de la fuente y devuelve algo que parece el acumulador

 // 1. create a concat reducing function that can be passed into `reduce` const concat = (acc, input) => acc.concat([input]) // note that [1,2,3].reduce(concat, []) would return [1,2,3] // transforming your reducing function by mapping // 2. create a generic mapping function that can take a reducing function and return another reducing function const mapping = (changeInput) => (reducing) => (acc, input) => reducing(acc, changeInput(input)) // 3. create your map function that operates on an input const getSrc = (x) => x.src const mappingSrc = mapping(getSrc) // 4. now we can use our `mapSrc` function to transform our original function `concat` to get another reducing function const inputSources = [{src:'one.html'}, {src:'two.txt'}, {src:'three.json'}] inputSources.reduce(mappingSrc(concat), []) // -> ['one.html', 'two.txt', 'three.json'] // remember this is really essentially just // inputSources.reduce((acc, x) => acc.concat([x.src]), []) // transforming your reducing function by filtering // 5. create a generic filtering function that can take a reducing function and return another reducing function const filtering = (predicate) => (reducing) => (acc, input) => (predicate(input) ? reducing(acc, input): acc) // 6. create your filter function that operate on an input const filterJsonAndLoad = (img) => { console.log(img) if(img.src.split('.').pop() === 'json') { // game.loadSprite(...); return false; } else { return true; } } const filteringJson = filtering(filterJsonAndLoad) // 7. notice the type of input and output of these functions // concat is a reducing function, // mapSrc transforms and returns a reducing function // filterJsonAndLoad transforms and returns a reducing function // these functions that transform reducing functions are "transducers", termed by Rich Hickey // source: http://clojure.com/blog/2012/05/15/anatomy-of-reducer.html // we can pass this all into reduce! and without any intermediate arrays const sources = inputSources.reduce(filteringJson(mappingSrc(concat)), []); // [ 'one.html', 'two.txt' ] // ================================== // 8. BONUS: compose all the functions // You can decide to create a composing function which takes an infinite number of transducers to // operate on your reducing function to compose a computed accumulator without ever creating that // intermediate array const composeAll = (...args) => (x) => { const fns = args var i = fns.length while (i--) { x = fns[i].call(this, x); } return x } const doABunchOfStuff = composeAll( filtering((x) => x.src.split('.').pop() !== 'json'), mapping((x) => x.src), mapping((x) => x.toUpperCase()), mapping((x) => x + '!!!') ) const sources2 = inputSources.reduce(doABunchOfStuff(concat), []) // ['ONE.HTML!!!', 'TWO.TXT!!!'] 

Aquí hay una solución divertida:

 /** * Filter-map. Like map, but skips undefined values. * * @param callback */ function fmap(callback) { return this.reduce((accum, ...args) => { let x = callback(...args); if(x !== undefined) { accum.push(x); } return accum; }, []); } 

Usar con el operador de enlace :

 [1,2,-1,3]::fmap(x => x > 0 ? x * 2 : undefined); // [2,4,6] 

Responda sans superfluous edge cases:

 const thingsWithoutNulls = things.reduce((acc, thing) => { if (thing !== null) { acc.push(thing); } return acc; }, []) 

TL; TR;

Creo que la forma más sencilla de omitir algunos elementos de la matriz es mediante el método filter () .

Al utilizar este método y la syntax de ES6 , puede escribir su código en una línea :

 var sources = images.filter(img => img.src.slice(-4) != "json").map(img => img.src); 

y esto te devolverá lo que quieras :

 ["img.png", "img.png"] 

¿Por qué no solo usar un bucle forEach?

 let arr = ['a','b','c','d','e']; let filtered = []; arr.forEach(x => { if (!x.includes('b')) filtered.push(x); }); // filtered === ['a','c','d','e']; 

Aquí hay un método de utilidad (compatible con ES5) que solo asigna valores no nulos (oculta la llamada a reducir):

 function mapNonNull(arr, cb) { return arr.reduce(function (accumulator, value, index, arr) { var result = cb.call(null, value, index, arr); if (result != null) { accumulator.push(result); } return accumulator; }, []); } var result = mapNonNull(["a", "b", "c"], function (value) { return value === "b" ? null : value; // exclude "b" }); console.log(result); // ["a", "c"] 

Array.prototype.flatMap es otra opción.

 images.flatMap(({src}) => src.endsWith('.json') && [] || src); 

Desde MDN :

flatMap se puede utilizar como una forma de agregar y eliminar elementos (modificar el número de elementos) durante un mapa. En otras palabras, le permite asignar muchos elementos a muchos elementos (al manejar cada elemento de entrada por separado), en lugar de siempre uno a uno. En este sentido, funciona como el contrario del filtro. Simplemente devuelva una matriz de 1 elemento para mantener el elemento, una matriz de elementos múltiples para agregar elementos o una matriz de 0 elementos para eliminar el elemento.

Javascript tiene muchos buenos JS marco (como Node.js AngularJS Vue.js React.js) es el mejor lenguaje de script.