DEV Community

Cover image for Domine o método Filter e simplifique sua lógica com arrays em Javascript
deMenezes
deMenezes

Posted on • Originally published at demenezes.dev

Domine o método Filter e simplifique sua lógica com arrays em Javascript

Você já passou café? Então será fácil aprender a usar o método filter em Javascript para filtrar dados de uma array. Veja como:

Você gosta de café?

Se pelo menos já passou café alguma vez na vida, vai ser bem fácil de entender esse conteúdo. Isso porque o filtro do café faz a mesma coisa que o método filter em Javascript.

o processo de filtrar água e pó de café e resultar em café

Você coloca dentro dele o pó de café e água. Ele segura o pó, e deixa a água passar.

Fim.

O filter em Javascript recebe uma array de elementos e filtra ela:

const ingredientes = [ 'pó de café', 'água' ];

const cafePassado = ingredientes.filter(function(ingrediente) {
  if (ingrediente === 'água') {
    return true;
  } else {
    return false
  }
});

console.log(cafePassado); // [ 'água' ]
Enter fullscreen mode Exit fullscreen mode

É claro que o resultado final não é apenas "água", e sim o café líquido. Mas entendeu né?

Esse é o básico que você precisa saber, continue lendo para entender mais alguns detalhes do filter.

Estrutura do método filter em Javascript

A estrutura desse método é muito parecida com a dos outros métodos de array.

Ao chamar o filter, você informa uma função callback que executa uma vez a cada item da array. No exemplo acima, a função callback é:

function(ingrediente) {
  if (ingrediente === 'água') {
    return true;
  } else {
    return false
  }
}
Enter fullscreen mode Exit fullscreen mode

Um ponto muito importante sobre a função callback é que ela deve retornar um valor booleano: true ou false. Esse retorno depende dos critérios que você quiser. No primeiro exemplo, o critério é o item deve ser igual a 'água'.

Os itens que atenderem aos requisitos farão parte da nova array. Logo:

  • Se todos os itens retornarem true, a nova array será idêntica à original, inclusive com a mesma quantidade de itens
  • Se todos os itens retornarem false, a nova array sempre será vazia []
  • Se houver pelo menos 1 true e 1 false, a nova array será menor que a array original, mas não vazia
  • A nova array nunca será maior que a original

Você percebeu que o return é algo importante aqui, né? E existe outro detalhe sobre ele.

O return do filter sempre é um booleano

Veja o exemplo abaixo:

const numbers = [ -3, -2, -1, 0, 1, 2, 3 ];

const result = numbers.filter(function(number) {
  return number;
});

console.log(result); // [ -3, -2, -1, 1, 2, 3 ];
Enter fullscreen mode Exit fullscreen mode

No primeiro exemplo fica muito claro que o retorno é um booleano.

Mas por que aqui eu retornei o próprio número? E por que a nova array tem todos os números menos o 0?

representação gráfica do filtro de números

O retorno deve ser booleano, mas você não precisa escrever true ou false explicitamente. Caso o valor não seja um booleano, o Javascript converte ele para poder decidir se insere o valor na nova array ou não. Esse processo de conversão se chama coerção de tipo.

Coerção de tipo é quando o Javascript precisa de um tipo de dado, porém você fornece outro tipo. Então ele faz a conversão para que tudo possa funcionar. Isso acontece com vários tipos de dados, e não apenas number ou booleano.

Esse é um assunto complexo e longo, mas importante em Javascript. Recomendo que você estude em algum momento.

Como o filter precisa retornar um booleano, ele converte o valor de number para boolean. Após a conversão, o filter segue com o trabalho.

No exemplo acima da array de números, a linha return number tem os seguintes valores:

return -3; // true
return -2; // true
return -1; // true
return 0;  // false
return 1;  // true
return 2;  // true
return 3;  // true
Enter fullscreen mode Exit fullscreen mode

Mais uma pílula de conhecimento sobre coerção: o Javascript converte zero em false, e os demais números em true. E é por isso que a nova array contém todos os números, menos o 0.


Se você não retornar nada, o resultados será uma array vazia.

Por quê?

Toda função retorna alguma coisa. Se você não retornar nada, a função retorna o valor padrão que é undefined. Durante a coerção de tipo, undefined vira false, e como você já viu, isso gera uma nova array vazia.

E se, enquanto decide que se insere o item na nova array, você quiser aplicar alguma alteração nele?

O filter não altera os itens da array

O filter apenas decide quais itens filtrar ou não, o método não altera eles.

Se você precisa alterar algum valor, precisará conectar o filter com outro método, como por exemplo o map:

const numbers = [ -3, -2, -1, 0, 1, 2, 3 ];

const result = numbers
  .filter(function(number) {
    return number;
  })
  .map(function(number) {
    return number * 2;
  });

console.log(result); // [ -6, -4, -2, 2, 4, 6 ]
Enter fullscreen mode Exit fullscreen mode

O último artigo aqui do blog foi sobre como manipular arrays em Javascript com o map. Recomendo a leitura para uma compreensão mais completa.

O código acima recebe a array de números [ -3, -2, -1, 0, 1, 2, 3 ] e usa o filter para filtrar os números que são true. Depois usa o map para multiplicar cada número restante por 2.

Diferente do filter, o map não faz coerção, porque ele não exige que o retorno seja um booleano. Ele apenas insere o valor que você retornou na nova array.

Agora conheça os três parâmetros da função callback do filter.

Os parâmetros da função callback

Essas são as ferramentas para trabalhar dentro do filter.

As funções callback dos exemplos que dei até agora, receberam apenas 1 parâmetro. Esse parâmetro representa cada item da array original.

Mas a função pode receber até 3 parâmetros, e você pode usar apenas aqueles que precisar.

Vou usar uma array com informações frutas para dar exemplos:

const fruits = [
  { name: 'Maçã',    color: 'Vermelha', weight: 150,  flavor: 'Doce',     format: 'Redonda',   vitamins: ['C', 'A'],  },
  { name: 'Manga',   color: 'Amarela',  weight: 200,  flavor: 'Doce',     format: 'Oval',      vitamins: ['C', 'A'],  },
  { name: 'Banana',  color: 'Amarela',  weight: 120,  flavor: 'Doce',     format: 'Alongada',  vitamins: ['C', 'B6'], },
  { name: 'Laranja', color: 'Laranja',  weight: 180,  flavor: 'Cítrico',  format: 'Redonda',   vitamins: ['C', 'A'],  },
  { name: 'Uva',     color: 'Roxa',     weight: 5,    flavor: 'Doce',     format: 'Esfera',    vitamins: ['C', 'K'],  },
  { name: 'Pera',    color: 'Amarela',  weight: 160,  flavor: 'Doce',     format: 'Pêra',      vitamins: ['C', 'K'],  },
  { name: 'Morango', color: 'Vermelha', weight: 10,   flavor: 'Cítrico',  format: 'Esfera',    vitamins: ['C', 'K'],  },
  { name: 'Abacaxi', color: 'Amarela',  weight: 1000, flavor: 'Cítrico',  format: 'Irregular', vitamins: ['C', 'B6'], },
  { name: 'Kiwi',    color: 'Verde',    weight: 100,  flavor: 'Agridoce', format: 'Oval',      vitamins: ['C', 'K'],  },
  { name: 'Cereja',  color: 'Vermelha', weight: 5,    flavor: 'Doce',     format: 'Esfera',    vitamins: ['C', 'A'],  }
];
Enter fullscreen mode Exit fullscreen mode

Uma rápida explicação:

  • Essa é uma array de frutas
  • Cada objeto contém as informações de uma fruta
  • As informações são nome, cor, peso (em gramas), sabor, formato e uma array de vitaminas daquela fruta

Veja agora exemplos com o primeiro parâmetro.

O parâmetro item

Esse você já está careca de ver.

O desafio aqui é: filtrar apenas as frutas na cor "Vermelha".

representação gráfica do filtro de cor vermelha

Para isso, a primeira coisa é descobrir a cor da fruta daquela iteração:

fruits.filter(function(fruit) {
  const color = fruit.color;
  console.log(color);
});
Enter fullscreen mode Exit fullscreen mode

Agora verifico se é a cor que desejo, e retorno true, caso contrário retorno false:

fruits.filter(function(fruit) {
  const color = fruit.color;

  if (color === 'Vermelha') {
    return true;
  } else {
    return false;
  }
});
Enter fullscreen mode Exit fullscreen mode

E você verá que o resultado é "Maçã", "Morango" e "Cereja", ou seja, frutas vermelhas.

Isso já resolve o desafio. Mas como dica adicional, é possível deixar esse código mais curto:

fruits.filter(fruit => fruit.color === 'Vermelha');
Enter fullscreen mode Exit fullscreen mode

As mudanças que fiz foram as seguintes:

  • Troquei a declaração normal da função callback para arrow function
  • Não criei a variável color, em vez disso, usei o valor diretamente em fruit.color
  • Em vez de retornar um booleano diretamente, retornei fruit.color === 'Vermelha'. Se essa comparação for verdadeira, o retorno será true, senão, será false

O código menor não necessariamente é melhor. Porém conforme você se acostuma com alguns códigos, vai perceber que não precisa escrever um bloco tão grande. Daqui em diante vou escrever o código maior, mas fique à vontade para fazer como quiser.


O segundo desafio é: filtrar frutas de cor "Amarela", sabor "Doce" e que tenha vitamina K.

representação gráfica do filtro de fruta amarela, sabor doce e com vitamina k

Você já aprendeu a adicionar uma condição, agora basta adicionar duas:

fruits.filter(function(fruit) {
  const color = fruit.color;
  const vitamins = fruit.vitamins;

  if (color === 'Amarela' && vitamins.includes('K')) {
    return true;
  } else {
    return false;
  }
});
Enter fullscreen mode Exit fullscreen mode

Para verificar a cor, fiz igualzinho ao primeiro desafio. Para verificar as vitaminas, usei o método de array includes que verifica se uma array tem um item.

E o resultado será apenas o objeto da fruta "Pera".


O terceiro e último desafio é: filtrar frutas de cor "Azul".

representação gráfica do filtro de frutas azuis

Ué?! Existe fruta azul? Sim, mas não na array do desafio.

O código você já sabe como é, porém esse desafio serve apenas para mostrar que o filter pode retornar uma array vazia:

fruits.filter(function(fruit) {
  if (fruit.color === 'Azul') {
    return true;
  } else {
    return false;
  }
});
Enter fullscreen mode Exit fullscreen mode

E o resultado é:

[]
Enter fullscreen mode Exit fullscreen mode

O segundo parâmetro que você vai aprender é só um "numerozinho".

O parâmetro index

Esse parâmetro é o índice do item da array.

Ele inicia em 0 e aumenta em 1 a cada iteração:

fruits.filter(function(fruit, index) {
  console.log(index);
});
Enter fullscreen mode Exit fullscreen mode

Esse código mostra no console o index de todos os itens. Como são 10 itens, vai de 0 a 9:

0
1
2
3
4
5
6
7
8
9
Enter fullscreen mode Exit fullscreen mode

O desafio é: filtrar frutas com formato de "Esfera", desde que seu index seja par.

representação gráfica de frutas no formato de esfera

O código começa assim:

fruits.filter(function(fruit, index) {

});
Enter fullscreen mode Exit fullscreen mode

Tenho em mãos agora o objeto fruit com as informações da fruta, e seu index.

Se eu fizer a operação index % 2 === 0 e o retorno for 0, significa que o número é par. Se retornar 1, o número é impar. Expliquei isso em detalhes no post sobre o método forEach em Javascript.

O desafio propôs duas condições: em relação ao formato e o index par. Veja como isso fica no código:

fruits.filter(function(fruit, index) {
  const format = fruit.format;
  const isEven = index % 2 === 0;

  if (format === 'Oval' && isEven) {
    return true;
  } else {
    return false;
  }
});
Enter fullscreen mode Exit fullscreen mode

O resultado será uma array apenas a fruta "Kiwi". A fruta "Manga" também faria parte, caso não houvesse a condição do index par.

Veja agora o último parâmetro da função callback.

O parâmetro array

Esse é o único parâmetro que não varia.

Ele sempre retorna a array original. Nos exemplos desse post, esse parâmetro é a array fruits, com as informações de todas as frutas.

Esse recurso é bom para quando você precisa de alguma informação da array para decidir se insere o item na nova array.

O primeiro desafio é um exemplo desse uso: filtrar frutas as quais seu formato só apareça 1 vez na lista toda, independente de qual seja esse formato.

representação gráfica do filtro de frutas em formato único

Como descobrir se um formato só existe uma vez na lista?

fruits.filter(function(fruit, index, array) {
  const format = fruit.format;

  let formatQuantity = 0;
  let i;

  for (i = 0; i < array.length; i++) {
    if (array[i].format === format) {
      formatQuantity = formatQuantity + 1;
    }
  }

  console.log(`O formato ${format} existe ${formatQuantity} vezes na lista`);
});
Enter fullscreen mode Exit fullscreen mode

Esse código vai te mostrar quantas vezes cada formato se repete na array. E assim será possível ver que apenas os formatos "Alongada", "Pera" e "Irregular" aparecem só uma vez. As outras aparecem duas ou três vezes. Assim você começa a ter uma noção do resultado final.

Agora vou remover os consoles e adicionar o return que não pode faltar:

fruits.filter(function(fruit, index, array) {
  const format = fruit.format;

  let formatQuantity = 0;
  let i;

  for (i = 0; i < array.length; i++) {
    if (array[i].format === format) {
      formatQuantity = formatQuantity + 1;
    }
  }

  if (formatQuantity === 1) {
    return true;
  } else {
    return false;
  }
});
Enter fullscreen mode Exit fullscreen mode

As frutas que o filter adicionou na array final foram:

  • Banana: formato "Alongada"
  • Pera: formato "Pera"
  • Abacaxi: formato "Irregular"

Agora, o último desafio desse artigo, vamos lá: filtrar frutas com mais de 150 gramas, e que essa fruta esteja na primeira metade da lista.

representação gráfica do filtro de frutas com mais de 150 gramas na primeira metade da lista

Para resolver isso, você vai precisar usar todos os parâmetros da array.

Vou começar com a informação do peso:

fruits.filter(function(fruit, index, array) {
  const weight = fruit.weight;
});
Enter fullscreen mode Exit fullscreen mode

E como descubro se a fruta está na primeira metade da lista: pelo index.

fruits.filter(function(fruit, index, array) {
  const weight = fruit.weight;
  const firstHalf = (array.length / 2) > (index + 1);
});
Enter fullscreen mode Exit fullscreen mode

A variável firstHalf informa se o item faz parte da primeira metade. Ele verifica se o tamanho da array dividido por 2 (ou seja, sua metade) é maior que o index + 1. O + 1 serve para ajustar o índice, já que ele inicia em zero.

Existem alguns problemas nesse código, como arrays com quantidade impar de itens. Por exemplo: em uma array de 9 itens, o quinto item faz parte da primeira ou segunda metade? Mas esse não é o foco desse artigo, então ignore isso.

O código final fica assim:

fruits.filter(function(fruit, index, array) {
  const weight = fruit.weight;
  const firstHalf = (array.length / 2) > (index + 1);

  if (weight > 150 && firstHalf) {
    return true;
  } else {
    return false;
  }
});
Enter fullscreen mode Exit fullscreen mode

E o resultado será "Manga" e "Laranja". Se não existisse o critério de estar na primeira metade da lista, você também veria "Pera" e "Abacaxi".

Mas apenas explicar como o filter funciona não basta, você precisa saber quando usar.

Como saber se preciso usar o filter

Mesmo que você tenha entendido tudo, é importante perceber o momento de chamar o filter no seu dia a dia.

Então criei uma linha raciocínio que você pode seguir.

Do que você precisa?

Se a resposta for uma array, o filter é um grande candidato.

Isso porque o que o filter retorna é uma array.

Caso você precise de apenas 1 item de dentro da array, o filter não é o melhor método, mas também serve. Veja um exemplo para pegar todas as frutas chamadas "Abacaxi":

const result = fruits.filter(function(fruit) {
  if (fruit.name === "Abacaxi") {
    return true;
  } else {
    return false;
  }
});

console.log(result[0]); // Informações do abacaxi
Enter fullscreen mode Exit fullscreen mode

O "problema" é que esse código retorna uma array com apenas um item, as informações do abacaxi. E para acessá-las você vai precisar usar a notação de colchetes [0].

Quando você precisa pegar apenas 1 item de dentro da array, a melhor forma é usar o método find. Mas isso fica para outro post.

Qual a quantidade de itens que quero na nova array?

Para que o filter seja uma opção, as respostas a essa pergunta devem ser:

  • Igual à array original
  • Menor que a array original
  • Aceito uma array vazia

E nunca pode ser: maior que a array original.

O que você tem?

Se a resposta também for uma array, o filter ganha mais força.

Isso porque como você pode ver na MDN, o filter é um método de array. Não é possível usar ele com objeto ou string, por exemplo.

Cada item na nova array é um clone dele na array original?

Se a resposta for sim, pode usar o filter à vontade.

Como falei no começo do artigo, o filter não altera os itens que ele itera. Ele apenas decide se insere o item ou não. Logo, os itens são clones deles na array original.

Lembre-se que, apesar do filter não alterar nada, você pode conectar ele com um map e "fazer chover" com o Javascript.

Callback

O método filter em Javascript funciona como um filtro de café.

Ele filtra uma array e retorna uma lista apenas com os itens que atendem aos requisitos que você definiu.

Ele recebe como parâmetro uma função callback, e o retorno dessa função define se o item fará parte da nova array (true) ou não (false).

Se você não retornar um booleano, o Javascript faz uma conversão do valor para esse tipo, a conhecida coerção de tipo. Se você não retornar nada, é como se retornasse undefined, ou false, e a nova array ficará vazia.

Ela sempre será:

  • Idêntica à original
  • Com menos itens, inclusive zero

O filter não altera os elementos individualmente, apenas decide se insere eles ou não na nova lista. Você pode alterá-los ao conectar o filter com o método map.

A função callback recebe 3 parâmetros:

  • Item: o próprio elemento da array naquela iteração
  • Index: um valor que inicia em 0 e aumenta de 1 em 1
  • Array: a própria array que você está iterando

Para saber se você precisa usar o filter, siga a seguinte linha de raciocínio:

  • Eu preciso de uma array
  • A quantidade de itens dessa array deve ser igual ou menor que a original
  • Tenho uma array em mãos
  • Cada item na array nova é um clone dela na array original

Seguindo esses passos, rapidamente você terá domínio do método filter.

Ele é extremamente útil no dia a dia. E conforme você pratica, fica mais fácil e legal de usá-lo.

Não tenho dúvida de que aprender o filter tornou meu código mais fácil de ler e direto ao ponto em vários aspectos. E espero que a compreensão do conteúdo possa fazer isso com o seu código também.

Se ficou alguma dúvida, deixe um comentário que será um prazer responder.

E se esse conteúdo te ajudou e você gostaria de dizer um obrigado, compartilhe esse conteúdo nas redes sociais ou mande para um amigo que precise 🤗.

Até a próxima!


Continue estudando:

Top comments (2)

Collapse
 
raulferreirasilva profile image
Raul Ferreira

Que artigo incrível, muito bom ter mais contatos com métodos array e soluções que demoraria pra desenvolver, muito bom ter contato com código bem explicados e que ajudam evoluir 🦤.

Collapse
 
demenezes profile image
deMenezes

Esses métodos de array são ótimos, evita o uso do for (particularmente não gosto muito), e deixam o código mais direto ao ponto.