Domine o método Filter e simplifique sua lógica com arrays em Javascript
Tags: filter, javascript, array, githubbrasil
Published: 2023-10-17 11:38:44

## 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é](https://demenezes.dev/_next/image/?url=https%3A%2F%2Fwww.datocms-assets.com%2F64896%2F1697480402-o-processo-de-filtrar-agua-e-po-de-cafe-e-resultar-em-cafe.png%3Fauto%3Dformat&w=3840&q=75)
 
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**:
 
```javascript
const ingredientes = [ 'pó de café', 'água' ];

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

console.log(cafePassado); // [ 'água' ]
```
 
É 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 é:
 
```javascript
function(ingrediente) {
  if (ingrediente === 'água') {
    return true;
  } else {
    return false
  }
}
```
 
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:
 
```javascript
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 ];
```
 
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](https://demenezes.dev/_next/image/?url=https%3A%2F%2Fwww.datocms-assets.com%2F64896%2F1697480440-3-2-1-0-1-2-3.png%3Fauto%3Dformat&w=3840&q=75)
 
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](https://www.freecodecamp.org/portuguese/news/coercao-de-tipo-em-javascript-explicada/).
 
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:
 
```javascript
return -3; // true
return -2; // true
return -1; // true
return 0;  // false
return 1;  // true
return 2;  // true
return 3;  // true
```
 
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:
 
```javascript
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 ]
```
 
O último artigo aqui do blog foi sobre [como manipular arrays em Javascript com o map](https://demenezes.dev/posts/map-javascript-array/). 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:
 
```javascript
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'],  }
];
```
 
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](https://demenezes.dev/_next/image/?url=https%3A%2F%2Fwww.datocms-assets.com%2F64896%2F1697480479-3-2-1-0-1-2-3-1.png%3Fauto%3Dformat&w=3840&q=75)
 
Para isso, a primeira coisa é descobrir a cor da fruta daquela iteração:
 
```javascript
fruits.filter(function(fruit) {
  const color = fruit.color;
  console.log(color);
});
```
 
Agora verifico se é a cor que desejo, e retorno `true`, caso contrário retorno `false`:
 
```javascript
fruits.filter(function(fruit) {
  const color = fruit.color;
 
  if (color === 'Vermelha') {
    return true;
  } else {
    return false;
  }
});
```
 
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:
 
```javascript
fruits.filter(fruit => fruit.color === 'Vermelha');
```
 
As mudanças que fiz foram as seguintes:
 
- Troquei a declaração normal da função callback para [arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
- 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](https://demenezes.dev/_next/image/?url=https%3A%2F%2Fwww.datocms-assets.com%2F64896%2F1697480499-3-2-1-0-1-2-3-2.png%3Fauto%3Dformat&w=3840&q=75)
 
Você já aprendeu a adicionar uma condição, agora basta adicionar duas:
 
```javascript
fruits.filter(function(fruit) {
  const color = fruit.color;
  const vitamins = fruit.vitamins;
 
  if (color === 'Amarela' && vitamins.includes('K')) {
    return true;
  } else {
    return false;
  }
});
```
 
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](https://demenezes.dev/_next/image/?url=https%3A%2F%2Fwww.datocms-assets.com%2F64896%2F1697480523-3-2-1-0-1-2-3-3.png%3Fauto%3Dformat&w=3840&q=75)
 
Ué?! Existe fruta azul? [Sim](https://www.google.com/search?q=existe+frita+azul%3F&rlz=1C1GCEU_pt-BRBR1015BR1015&oq=existe+frita+azul%3F&gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIICAEQABgNGB4yCggCEAAYBRgNGB4yCggDEAAYCBgNGB7SAQg0MzcwajBqN6gCALACAA&sourceid=chrome&ie=UTF-8), 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:
 
```javascript
fruits.filter(function(fruit) {
  if (fruit.color === 'Azul') {
    return true;
  } else {
    return false;
  }
});
```
 
E o resultado é:
 
```javascript
[]
```
 
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:
 
```javascript
fruits.filter(function(fruit, index) {
  console.log(index);
});
```
 
Esse código mostra no console o index de todos os itens. Como são 10 itens, vai de 0 a 9:
 
```javascript
0
1
2
3
4
5
6
7
8
9
```
 
O desafio é: *filtrar frutas com formato de "Esfera", desde que seu index seja par*.
 
![representação gráfica de frutas no formato de esfera](https://demenezes.dev/_next/image/?url=https%3A%2F%2Fwww.datocms-assets.com%2F64896%2F1697480548-3-2-1-0-1-2-3-4.png%3Fauto%3Dformat&w=3840&q=75)
 
O código começa assim:
 
```javascript
fruits.filter(function(fruit, index) {

});
```
 
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](https://demenezes.dev/posts/como-usar-foreach-javascript-exemplos/#o-par%C3%A2metro-index-da-funcao-callback).
 
O desafio propôs duas condições: em relação ao formato e o index par. Veja como isso fica no código:
 
```javascript
fruits.filter(function(fruit, index) {
  const format = fruit.format;
  const isEven = index % 2 === 0;
  
  if (format === 'Oval' && isEven) {
    return true;
  } else {
    return false;
  }
});
```
 
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](https://www.google.com/search?gs_ssp=eJzj4tLP1TcwKswrLjIwYHRg8OIpKS0pyVRIKwJRAHcqCPU&q=tutti+frutti&rlz=1C1GCEU_pt-BRBR1015BR1015&oq=tutti&gs_lcrp=EgZjaHJvbWUqCggBEC4YsQMYgAQyDwgAEEUYORiDARixAxiABDIKCAEQLhixAxiABDIHCAIQABiABDITCAMQLhiDARivARjHARixAxiKBTIHCAQQABiABDIKCAUQABixAxiABDIKCAYQABixAxiABDIHCAcQABiABDITCAgQLhiDARivARjHARixAxiKBTIHCAkQABiABNIBCDI2ODlqMGo3qAIAsAIA&sourceid=chrome&ie=UTF-8).
 
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](https://demenezes.dev/_next/image/?url=https%3A%2F%2Fwww.datocms-assets.com%2F64896%2F1697480580-3-2-1-0-1-2-3-5.png%3Fauto%3Dformat&w=3840&q=75)
 
Como descobrir se um formato só existe uma vez na lista?
 
```javascript
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`);
});
```
 
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:
 
```javascript
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;
  }
});
```
 
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](https://demenezes.dev/_next/image/?url=https%3A%2F%2Fwww.datocms-assets.com%2F64896%2F1697480603-3-2-1-0-1-2-3-6.png%3Fauto%3Dformat&w=3840&q=75)
 
Para resolver isso, você vai precisar usar todos os parâmetros da array.
 
Vou começar com a informação do peso:
 
```javascript
fruits.filter(function(fruit, index, array) {
  const weight = fruit.weight;
});
```
 
E como descubro se a fruta está na primeira metade da lista: pelo index.
 
```javascript
fruits.filter(function(fruit, index, array) {
  const weight = fruit.weight;
  const firstHalf = (array.length / 2) > (index + 1);
});
```
 
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:
 
```javascript
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;
  }
});
```
 
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":
 
```javascript
const result = fruits.filter(function(fruit) {
  if (fruit.name === "Abacaxi") {
    return true;
  } else {
    return false;
  }
});

console.log(result[0]); // Informações do abacaxi
```
 
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](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/filter). 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:
 
- [https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/filter](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
- [https://www.freecodecamp.org/portuguese/news/coercao-de-tipo-em-javascript-explicada/](https://www.freecodecamp.org/portuguese/news/coercao-de-tipo-em-javascript-explicada/)
- [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
- [https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/filter](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)