Eu gostaria de filtrar uma matriz de itens usando a map()
função. Aqui está um snippet de código:
var filteredItems = items.map(function(item)
{
if( ...some condition... )
{
return item;
}
});
O problema é que os itens filtrados ainda usam espaço na matriz e eu gostaria de eliminá-los completamente.
Qualquer ideia?
EDIT: Obrigado, esqueci filter()
, o que eu queria na verdade é um filter()
então a map()
.
EDIT2: Obrigado por apontar isso map()
e filter()
não são implementados em todos os navegadores, embora meu código específico não tenha a intenção de ser executado em um navegador.
javascript
functional-programming
data-manipulation
client-side
Vincent Robert
fonte
fonte
Respostas:
Você deve usar o
filter
método em vez de mapear, a menos que queira modificar os itens na matriz, além da filtragem.por exemplo.
var filteredItems = items.filter(function(item) { return ...some condition...; });
[Editar: é claro que você sempre pode fazer
sourceArray.filter(...).map(...)
para filtrar e modificar]fonte
map
não sofre mutaçãomap
.x=[1,2,3];y = x.map(z => z*2);console.log(x,y);
Inspirado por escrever esta resposta, acabei expandindo mais tarde e escrevendo uma postagem no blog que tratava disso com detalhes cuidadosos. Recomendo verificar isso se você quiser desenvolver um entendimento mais profundo de como pensar sobre esse problema - tento explicá-lo peça por peça e também fornecer uma comparação JSperf no final, passando por considerações de velocidade.
Dito isso, o tl; dr é o seguinte: para realizar o que você está pedindo (filtragem e mapeamento em uma chamada de função), você usaria
Array.reduce()
.No entanto, a abordagem mais legível e (menos importante) geralmente significativamente mais rápida 2 é usar apenas o filtro e o mapa encadeados:
[1,2,3].filter(num => num > 2).map(num => num * 2)
O que se segue é uma descrição de como
Array.reduce()
funciona e como pode ser usado para filtrar e mapear em uma iteração. Novamente, se isso estiver muito condensado, eu recomendo fortemente que você veja a postagem do blog no link acima, que é uma introdução muito mais amigável com exemplos claros e progressão.Você fornece a reduzir um argumento que é uma função (geralmente anônima).
Essa função anônima leva dois parâmetros - um (como as funções anônimas passadas para map / filter / forEach) é o iteratário a ser operado. Há outro argumento para a função anônima passada reduzir, no entanto, que essas funções não aceitam, e é o valor que será passado entre as chamadas de função, geralmente referido como memo .
Observe que enquanto Array.filter () recebe apenas um argumento (uma função), Array.reduce () também assume um segundo argumento importante (embora opcional): um valor inicial para 'memo' que será passado para a função anônima como seu primeiro argumento e, subsequentemente, pode ser alterado e transmitido entre as chamadas de função. (Se não for fornecido, então 'memo' na primeira chamada de função anônima será, por padrão, o primeiro iteratário, e o argumento 'iteratário' será, na verdade, o segundo valor na matriz)
Em nosso caso, passaremos um array vazio para iniciar e, em seguida, escolheremos se injetamos nosso iteratê em nosso array ou não com base em nossa função - este é o processo de filtragem.
Por fim, retornaremos nosso 'array em andamento' em cada chamada de função anônima e reduzir pegará esse valor de retorno e o passará como um argumento (chamado memo) para sua próxima chamada de função.
Isso permite que o filtro e o mapa ocorram em uma iteração, reduzindo nosso número de iterações necessárias pela metade - apenas fazendo o dobro de trabalho em cada iteração, então nada é realmente salvo além de chamadas de função, que não são tão caras em javascript .
Para uma explicação mais completa, consulte os documentos do MDN (ou minha postagem referenciada no início desta resposta).
Exemplo básico de uma chamada Reduce:
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)]
versão mais sucinta:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Observe que o primeiro iteratee não era maior que um e, portanto, foi filtrado. Observe também o initialMemo, nomeado apenas para deixar clara sua existência e chamar a atenção para ele. Mais uma vez, ele é passado como 'memo' para a primeira chamada de função anônima e, em seguida, o valor retornado da função anônima é passado como o argumento 'memo' para a próxima função.
Outro exemplo do caso de uso clássico para memo seria retornar o menor ou o maior número em um array. Exemplo:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val) // ^this would return the largest number in the list.
Um exemplo de como escrever sua própria função de redução (isso geralmente ajuda a entender funções como essas, eu acho):
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; }
A implementação real permite acesso a coisas como o índice, por exemplo, mas espero que isso ajude você a ter uma noção descomplicada de sua essência.
fonte
reduce
é que, ao contrário defilter
+map
, o retorno de chamada pode receber um argumento de índice que é o índice do array original, e não aquele filtrado.Não é isso que o mapa faz. Você realmente quer Array.filter . Ou se você realmente deseja remover os elementos da lista original, você precisará fazer isso imperativamente com um loop for.
fonte
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 )
fonte
var arr = [1,2,"xxx", "yyy"]; arr = arr.filter(function(e){ return e!="xxx" }) console.log(arr)
Você deve observar, entretanto, que
Array.filter
não é compatível com todos os navegadores, portanto, você deve prototipar://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; }; }
E, fazendo isso, você pode criar um protótipo de qualquer método de que precise.
fonte
a instrução a seguir limpa o objeto usando a função map.
var arraytoclean = [{v:65, toberemoved:"gronf"}, {v:12, toberemoved:null}, {v:4}]; arraytoclean.map((x,i)=>x.toberemoved=undefined); console.dir(arraytoclean);
fonte
Acabei de escrever a intersecção da matriz que lida corretamente com duplicatas
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' ]
fonte
Primeiro você pode usar o mapa e com o encadeamento você pode usar o 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; } });
fonte