Métodos do Array: Filter - Javascript

front-end

tags:

  • javascript
  • ES6
  • array

Postado em 02/11/2018

Olá! No post de hoje vou continuar falando sobre os métodos de manipulação de arrays em Javascript. Desta vez vou falar sobre o método filter, que pode ser bastante usado no dia a dia quando precisamos (como o próprio nome sugere) filtrar itens em um array.

Um contexto geral

O método filter é um dos métodos de manipulação de arrays que segue o conceito da programação funcional. Seria possível alcançar o mesmo resultado obtido pelo filter usando um laço for, mas como citei em meu post anterior, um laço desse tipo adiciona uma complexidade maior no código, como variáveis de controles e acesso ao array através de index. Neste post vou mostar as duas abordagens para podermos compará-las.

Não podemos esquecer de que o método filter não altera o array original, ele gera um array novo, de acordo com os itens do array original e a função passada como callback.

Lembrando que nos exemplos vou usar Arrow Functions, se você tiver alguma dúvida nesse assunto, dê uma olhada neste post sobre Arrow Functions.

Definição de filter()

Como de costume, vou deixar aqui a definição da documentação da MDN:

O método filter() cria um novo array com todos os elementos que passaram no teste implementado pela função fornecida.

E o que isso significa? Basicamente o que vai acontecer é o seguinte: vamos passar por cada item do array e vamos aplicar uma função nele (essa função é chamada de callback). Essa função deverá retornar true ou false, se o retorno for true este item estará no novo array gerado. Se for false o item não estará no novo array.

Bom, teoria é importante, mas geralmente fica mais fácil de entender vendo o código. Então vamos lá :D

De maneira bem resumida, o callback é uma função. E essa função será executada para cada item do array. Vamos usar como exemplo uma função que retorna true se um número é par e false caso não seja par:

const par = x => x % 2 === 0

par(0) // true
par(1) // false
par(2) // true
par(3) // false

Vamos usar essa função nos exemplos a seguir.

Começando usando o for

Vamos realizar a missão de pegar um array com vários números e selecionar somente os números pares, começando usando o for():

const par = x => x % 2 === 0

const numeros = [1, 2, 3, 4, 20, 22, 38, 41]

let pares = []

for (i = 0; i < numeros.length; i++) {
  if (par(numeros[i])) {
    pares.push(numeros[i])
  }
}
console.log(pares)
//Array(5)[ 2, 4, 20, 22, 38 ]

No final a gente conseguiu atingir nosso objetivo: obtivemos um array somente com os número pares. Porém o for tem alguns pontos negativos, como a complexidade do código. Temos que instanciar o array pares antes de inciar o laço, além disso temos que iniciar uma variável de controle i e acessar o array numeros através do index. Também temos de fazer um if para aí sim fazer um .push() no array pares.

Agora vamos usar uma abordagem diferente para resolver o mesmo problema.

Usando filter

Nosso objetivo será o mesmo, vamos obter somente os números pares de um array com números:

const par = x => x % 2 === 0

const numeros = [1, 2, 3, 4, 20, 22, 38, 41]

const pares = numeros.filter(par)

console.log(pares)
//Array(5)[ 2, 4, 20, 22, 38 ]

Vamos entender o que aconteceu. O método filter faz uma iteração para cada item do array (nesse caso numeros). Cada item será passada como parâmetro para a função que foi passada como callback para o filter (nesse caso par()). Se a função retornar true o item será retornado no novo array gerado (nesse caso pares).

Dessa forma conseguimos obter o mesmo resultado com um código mais simples. Podemos deixar esse código um pouco mais enxuto se, ao invés de criarmos a função par passarmos ela diretamente para o filter:

const numeros = [1, 2, 3, 4, 20, 22, 38, 41]

const pares = numeros.filter(x => x % 2 === 0)

console.log(pares)
//Array(5)[ 2, 4, 20, 22, 38 ]

Se não precisarmos reutilizar a função par em outras partes do código, essa abordagem é bastante útil.

Algumas considerações

O método filter com certeza é muito útil e prático para o uso no dia a dia, porém tem alguns pontos que precisam ser considerados. Por exemplo se quisessemos obter dois array, um com números pares e outro com os números ímpares, teríamos que fazer o filter duas vezes, com duas funções diferentes. Já usando o for poderíamos fazer em um único laço.

Usando for:

const numeros = [1, 2, 3, 4, 20, 22, 38, 41]

let pares = []
let impares = []

for (i = 0; i < numeros.length; i++) {
  if (numeros[i] % 2 === 0) {
    pares.push(numeros[i])
  } else {
    impares.push(numeros[i])
  }
}

console.log(pares)
//Array(5) [ 2, 4, 20, 22, 38 ]

console.log(impares)
//Array(3) [ 1, 3, 41 ]

Com filter:

const numeros = [1, 2, 3, 4, 20, 22, 38, 41]

const pares = numeros.filter(x => x % 2 === 0)

const impares = numeros.filter(x => x % 2 !== 0)

console.log(pares)
//Array(5) [ 2, 4, 20, 22, 38 ]

console.log(impares)
//Array(3) [ 1, 3, 41 ]

Nesses casos precisamos fazer uma escolha entre um código mais "limpo" e um código mais performático. Não existe uma resposta certa. As duas abordagens alcançam o mesmo resultado e cada uma possui suas vantagens e desvantagens.

Mais alguns exemplos

Como todos nossos exemplos até agora foram bastante simples, vou deixar aqui mais alguns exemplos em situações diferentes. Nesses exemplos vou mostrar apenas a aplicação do filter, sem levar em consideração a implementação com o for.

Filtrando um array de objetos

Vamos supor que temos um array com vários objetos que representam pessoas, com seus nomes e idade. Vamos obter um array com as pessoas que ainda não estejam na maioridade (com menos de 18 anos) e outro array com as pessoas idosas (com 60 anos ou mais).

const pessoas = [
  {
    nome: "João",
    idade: 50,
  },
  {
    nome: "Andrea",
    idade: 10,
  },
  {
    nome: "Marcos",
    idade: 70,
  },
  {
    nome: "Geovana",
    idade: 65,
  },
  {
    nome: "Everton",
    idade: 36,
  },
  {
    nome: "Roberta",
    idade: 47,
  },
  {
    nome: "André",
    idade: 9,
  },
  {
    nome: "Raquel",
    idade: 83,
  },
  {
    nome: "Valdir",
    idade: 29,
  },
  {
    nome: "Helena",
    idade: 30,
  },
]

const menosDe18Anos = pessoas.filter(pessoa => pessoa.idade < 18)
const maisDe60Anos = pessoas.filter(pessoa => pessoa.idade >= 60)

console.log(menosDe18Anos)
/*
[
{ nome: 'Andrea', idade: 10 },
{ nome: 'André', idade: 9 }
]
*/
console.log(maisDe60Anos)
/*
[
{ nome: 'Marcos', idade: 70 },
{ nome: 'Geovana', idade: 65 },
{ nome: 'Raquel', idade: 83 },
]
*/

Filtrando strings

Usando o mesmo array pessoas do exemplo anterior, vamos filtrar as pessoas que tem a letra "r" no nome (em qualquer parte, não apenas no começo). Para isso vamos usar os métodos toLowerCase() (pois "R" é difente de "r") e includes() da classe String. Se tiver dúvidas, você pode conferir a documentação do toLowerCase e do includes.

//o mesmo array pessoas usado no exemplo anterior

const pessoasComRNoNome = pessoas.filter(pessoa =>
  pessoa.nome.toLowerCase().includes("r")
)

console.log(pessoasComRNoNome)
/*
[
{ nome: "Andrea", idade: 10 },
{ nome: "Marcos", idade: 70 },
{ nome: "Everton", idade: 36 },
{ nome: "Roberta", idade: 47 },
{ nome: "André", idade: 9 },
{ nome: "Raquel", idade: 83 },
{ nome: "Valdir", idade: 29 }
]
*/

Filtrando com base em outro array

Para esse exemplo vamos considerar dois arrays. Um deles terá a lista com as capitais dos estados brasileiros. O segundo array, será uma lista com as 30 cidades mais populosas do Brasil. Nosso objetivo aqui é descobrir quais são as capitais que estão entre as 30 cidades mais populosas do país.

const capitais = [
  "Rio Branco",
  "Maceió",
  "Macapá",
  "Manaus",
  "Salvador",
  "Fortaleza",
  "Brasília",
  "Vitória",
  "Goiânia",
  "São Luís",
  "Cuiabá",
  "Campo Grande",
  "Belo Horizonte",
  "Belém",
  "João Pessoa",
  "Curitiba",
  "Recife",
  "Teresina",
  "Rio de Janeiro",
  "Natal",
  "Porto Alegre",
  "Porto Velho",
  "Boa Vista",
  "Florianópolis",
  "São Paulo",
  "Aracaju",
  "Palmas",
]

const cidadesMaisPopulosas = [
  "São Paulo",
  "Rio de Janeiro",
  "Salvador",
  "Brasília",
  "Fortaleza",
  "Belo Horizonte",
  "Manaus",
  "Curitiba",
  "Recife",
  "Porto Alegre",
  "Belém",
  "Goiânia",
  "Guarulhos",
  "Campinas",
  "São Luís",
  "São Gonçalo",
  "Maceió",
  "Duque de Caxias",
  "Natal",
  "Campo Grande",
  "Teresina",
  "São Bernardo do Campo",
  "Nova Iguaçu",
  "João Pessoa",
  "Santo André",
  "Osasco",
  "São José dos Campos",
  "Jaboatão dos Guararapes",
  "Ribeirão Preto",
  "Uberlândia",
]

const capitiaisMaisPopulosas = capitais.filter(capital =>
  cidadesMaisPopulosas.includes(capital)
)

console.log(capitiaisMaisPopulosas)
/*
Array(18) [
"Maceió",
"Manaus",
"Salvador",
"Fortaleza",
"Brasília",
"Goiânia",
"São Luís",
"Campo Grande",
"Belo Horizonte",
"Belém",
"João Pessoa",
"Curitiba",
"Recife",
"Teresina",
"Rio de Janeiro",
"Natal",
"Porto Alegre",
"São Paulo"
]
*/

Resumindo

O método filter segue os seguintes passos:

  1. É feita uma iteração para cada item do array;
  2. Em cada iteração, uma função (o callback) é executado passando o item da iteração como parâmetro;
  3. O item da iteração é armazenado somente se a função de callback retornar true;
  4. Ao final de todas as iterações, um novo array é retornado com os elementos armazenados no passo 3.

Basicamente, usamos o filter para obtermos apenas os itens de um array que satisfaçam uma condição que é determinada pela função de callback.

Espero que esse post tenha te ajudado a entender um pouco melhor sobre o método filter. Se tiver alguma dúvida ou sugestão de melhoria, é só deixar um comentário ou falar comigo nas redes sociais ;)

Compartilhe:

posts relacionados

Falando um pouco sobre Arrow Functions

Arrow function possui uma sintaxe mais curta, além de não fazer o bind do this em seu escopo.

ver post

Métodos do Array: map - Javascript

O método map em Javascript recebe uma função de callback e invoca ela para cada elemento do array, retornando um novo array.

ver post