Covil Do Dev

Utilizando filter() em JavaScript

Aprenda a filtrar objetos em um Array com o método filter() do JavaScript. Neste artigo o método filter() é apresentado com exemplos práticos e úteis de sua utilização.

Filtrar informações é uma das tarefas mais importantes e recorrentes enquanto programamos.

Computadores não seriam tão úteis se tivéssemos que vasculhar tudo manualmente, portanto filtrar os dados é uma tarefa comum e indispensável, permitindo que o usuário final reduza seu espaço de pesquisa a um nível aceitável.

JavaScript é a principal linguagem de front-end e em toda aplicação WEB será o primeiro contato do usuário com a aplicação.

Em JavaScript, o método filter() nos permite filtrar items contidos em um array, isso é feito iterando sobre os valores existentes e retornando um novo array apenas com aqueles objetos que atendem a determinados critérios.

A função filter() executa uma expressão condicional em cada entrada em uma matriz:

  • Se essa condicional for avaliada como true, o elemento será adicionado à matriz de saída.
  • Se a condição falhar, o elemento não será adicionado à matriz de saída.

Neste guia, veremos como trabalhar com o método filter() do JavaScript.

Primeiro, vamos nos familiarizar com o método, sua sintaxe e argumentos.

Em seguida, veremos vários exemplos práticos de tarefas que são facilmente abordadas com o método.

E por fim vamos compará-lo com um método alternativo(find()) e avaliar o seu desempenho.

ad

Valores de sintaxe e de parâmetro

A sintaxe é direta:

const arrayFiltrada = arrayOriginal.filter(funcaoFiltradora(element, index, array), context)

A funcaoFiltradora pode ser realmente qualquer função/predicado/condição arbitrária, desde que retorne um valor booleano, com base no valor de element.

Tecnicamente, ele não precisa utilizar o element em sua definição, mas isso provavelmente não seria uma função de filtragem muito útil.

O index e o array são opcionais, e você provavelmente não precisará usar array na prática.

index é o índice do item atual e array é um ponteiro para a matriz original.

Importante notar que a função de filtro constrói uma nova matriz e retorna todos os objetos que atendem ao critério fornecido no retorno de chamada. Ela não altera a matriz original.

Como o filter() do JavaScript funciona

Vamos dar uma olhada no método filter() em ação.

Nas versões anteriores do JS(antes do ES6) uma função de retorno de chamada seria usada como:

const numeros = [1, 2, 3, 4, 5, 6];
const numerosFiltrados = numeros.filter(function (numero) {
    return numero > 3;
});

console.log(numerosFiltrados); // [4, 5, 6]

A partir do ES6, podemos simplificar isso como uma Arrow function:

const numeros = [1, 2, 3, 4, 5, 6];
const numerosFiltrados = numeros.filter((numero) => {
    return numero > 3;
});

console.log(numerosFiltrados); // [4, 5, 6]

Ou, você pode simplificar a função para ser apenas uma condicional:

const numeros = [1, 2, 3, 4, 5, 6];
const numerosFiltrados = numeros.filter((numero) => numero > 3);
console.log(numerosFiltrados); // [4, 5, 6]

Como usar o objeto context com filter()

O método filter() pode aceitar um objeto adicional opcional: context.

filter(funcaoFiltradora, context);

O objeto pode ser referenciado usando a palavra-chave this de dentro da funcaoFiltradora, e context representa, bem, tudo o que passamos como contexto para o filtro.

Vamos dar uma olhada em um exemplo!

Classificaremos uma lista de menu, removendo todos os itens com preços que não estejam entre 15 e 25.

A faixa de preço é um objeto separado, que passamos para filter() o contexto. De certa forma é normalmente usado para definir um objeto de "configuração", contendo valores que podemos acessar genericamente, sem codificá-los:

const menu = [
    {
        name: "Panquecas",
        price: 15.99
    },
    {
        name: "PF",
        price: 13.99
    },
    {
        name: "Milkshake",
        price: 6.99
    },
    {
        name: "Feijoada",
        price: 20.99
    },
    {
        name: "Chambari",
        price: 22.99
    }
];

let priceRange = {
    lower: 15,
    upper: 25
};

Agora, vamos ultilizar o filter() com a lista de menu, passando o priceRangecomo o context:

let menuFiltrado = menu.filter(function (menu) {
    return menu.price >= this.lower && menu.price <= this.upper;
}, priceRange);

console.log(menuFiltrado);

Isto resulta em:

[
    {
        name: "Panquecas",
        price: 15.99
    },
    {
        name: "Feijoada",
        price: 20.99
    },
    {
        name: "Chambari",
        price: 22.99
    }
]

Como usar o parâmetro de índice(index)

O index pode ser usado para avaliar a posição de um elemento na matriz original.

Por exemplo, poderíamos filtrar pela posição dos elementos:

const users = ["John", "Doe", "Stephen", "Matt", "Abigail", "Susu"];

const topThree = users.filter((element, index) => {
    return index <= 2;
});

console.log(topThree); // ["John", "Doe", "Stephen"]

Embora isso também possa ser alcançado acessando os últimos N elementos de uma matriz, o índice pode desempenhar outras funções e não ser o único critério pelo qual filtrar.

Como usar o parâmetro array

O parâmetro array faz referência à matriz original que estamos filtrando.

Como você está iterando pela matriz de qualquer maneira, normalmente ficará satisfeito sem usar o parâmetro array, mas pode ser útil se a lógica depender de algum estado ou propriedade da própria matriz:

const competitors = ["John", "Doe", "Stephen", "Matt", "Abigail", "Susu"];

function selectWinners(name, index, array) {

    if (array.length > 3 && name.includes('a')) {
        return true;
    } else {
        return false;
    }
}

let lselectLoosers = competitors.filter((name, index, array) =>
    selectWinners(name, index, array)
);

console.log(lselectLoosers); // ["Matt", "Abigail", "Susu"]

Outro exemplo poderia ser se quisermos obter metade dos elementos de um array.

Nesse caso, podemos usar o array original para obter o total de elementos para filtrar os elementos com base no valor do índice:

const halfArray = function (element, index, array) {
    const half = Math.floor(array.length / 2);
    return index < half;
};

Agora podemos filtrar usando halfArray:

const names = ["John", "Doe", "Stephen", "Matt", "Abigail", "Susu"];
const halfNames = names.filter(halfArray);
console.log(halfNames); // ["John", "Doe", "Stephen"]

O método filter() aceita uma função de predicado(filtradora), que é executada em todos os elementos do array.

Baseado no valor booleano de retorno, o element é colocado ou não em um novo array de saída.

No final da iteração, apenas o novo array resultante é retornado, filtrado pelos critérios definidos no função de predicado.

Um objeto context pode ser passado e muitas vezes é usado para definir um objeto de "configuração" que armazena valores dinâmicos usados durante a filtragem.

O index refere-se à posição do elemento atual no array original, e o array é uma referência ao array original.

Exemplos

Com os conceitos básicos já dominados, vamos ver alguns exemplos práticos de utilização do método filter().

Filtrar uma matriz de objetos por valor

Filtrar um array de objetos por algum valor que eles contêm é uma das aplicações mais comuns do método filter().

Lidar com objetos não é muito diferente de trabalhar com outros tipos de dados!

Por exemplo, digamos que temos uma matriz de objetos de aluno, com alguns campos.

D igamos que você também queira filtrar os alunos por aqueles que se formaram no ano atual(obtido por Date().getFullYear()).

Você pode facilmente comparar o graduationYear de cada um element com o ano atual:

const students = [
    {firstName: "John", lastName: "Doe", graduationYear: 2022},
    {firstName: "Stephen", lastName: "Matt", graduationYear: 2023},
    {firstName: "Abigail", lastName: "Susu", graduationYear: 2022}
];

const currentYear = new Date().getFullYear();

let graduatingStudents = students.filter((element) => {
    if (element.graduationYear === currentYear) {
        return element;
    }
});

console.log(graduatingStudents);

Isto resulta em:

[
    {
        firstName: "John",
        lastName: "Doe",
        graduationYear: 2022
    },
    {
        firstName: "Abigail",
        lastName: "Susu",
        graduationYear: 2022
    }
]

Filtrando números primos

Vamos continuar com um exercício simples, filtrar números primos!

Vamos definir uma lista com um número definido de inteiros, e então utilizar o método filter():

const myArray = [-7, -5, -2, 2, 1, 3, 12, 14, 13, 15, 70, 17, 33, 25, 27, 30, 97];

const primeNumbers = myArray.filter((element) => {
    for (let i = 2; element > i; i++) {
        if (element % i === 0) {
            return false;
        }
    }
    return element > 1;
});

console.log(primeNumbers); // [2, 3, 13, 17, 97]

Você também pode, é claro, definir uma função primeNumbers() que aceite um elemento e retorne true ou false com base no fato de o elemento ser primo ou não e, em seguida, usar esse método na chamada filter(), se for chamá-lo várias vezes:

const numbers = [-7, -5, -2, 2, 1, 3, 12, 14, 13, 15, 70, 17, 33, 25, 27, 30, 97];

function findPrimeNumbers(element) {
    for (let i = 2; element > i; i++) {
        if (element % i === 0) {
            return false;
        }
    }
    return element > 1;
}

console.log(numbers.filter(findPrimeNumbers)); // [2, 3, 13, 17, 97]
Como filtrar números de uma matriz

Filtrar números em uma matriz, entre outros elementos, é tão fácil quanto verificar se uma variável é um número e retornar um valor booleano:

const isNumber = function (element) {
    return Number.isFinite(element);
};

Agora podemos chamar nosso método de filtro com a função reutilizável:

const random = ['1', 'blue', 2, '-4', 0, true, -3.4];
const numbers = random.filter(isNumber);
console.log(numbers); // [2, 0, -3.4]

O método acima não é útil para números que são representados por strings, portanto, outro método pode ser primeiro converter o elemento em um número, se aplicável(parseFloat()) e verificar o valor convertido com Number.isFinite():

const isNumber = function (element) {
    return Number.isFinite(parseFloat(element));
};

const random = ['1', 'blue', 2, '-4', 0, true, -3.4];
const numbers = random.filter(isNumber);
console.log(numbers); // ["1", 2, "-4", 0, -3.4]

método dfilter() vs find()

Vale a pena tirar um momento para destinguir para o o filter() é usado e o que não é usado.

Filtrar uma lista com base em um ou mais critérios normalmente inclui o retorno de uma sublista, que se ajusta aos critérios.

Mais raramente, um único elemento, se os critérios forem muito rigorosos.

Quando você estiver procurando por um elemento em uma lista, você filtrará tudo, exceto o elemento de destino, retornado em uma lista.

Um ajuste mais natural para o último caso é utilizar o método find(), em vez do filter().

  • filter(): retorna uma lista de todos os elementos que "passam" o predicado
  • find(): retorna o primeiro objeto que "passa" o predicado

Suponha que você tenha uma matriz de menu com diferentes categorias:

const menu = [
    {
        name: "buttermilk pancakes",
        category: "breakfast",
        price: 15.99,
        status: "available"
    },
    {
        name: "diner double",
        category: "lunch",
        price: 13.99,
        status: "available"
    },
    {
        name: "godzilla milkshake",
        category: "shakes",
        price: 6.99,
        status: "available"
    },
    {
        name: "country delight",
        category: "breakfast",
        price: 20.99,
        status: "86"
    },
    {
        name: "egg attack",
        category: "lunch",
        price: 22.99,
        status: "available"
    }
];

São 8h e o restaurante serve apenas itens de café da manhã até as 10h. Você desejará filtrar os itens que não são do café da manhã:

let breakfastMenu = menu.filter((menu) => menu.category === "breakfast");
console.log(breakfastMenu);

Isto resulta em:

[
    {
        name: "buttermilk pancakes",
        category: "breakfast",
        price: 15.99,
        status: "available"
    },
    {
        name: "country delight",
        category: "breakfast",
        price: 20.99,
        status: "86"
    }
]

Agora, digamos que alguém está querendo pedir um country delight.

A sublista é curta o suficiente para percebermos que o status é 86, mas com listas mais longas - podemos querer verificar se este item, quando encontrado, está disponível ou não:

const delight = menu.find((menu) => menu.name === "country delight");

if (delight.status !== "86") {
    console.log('Available!');
} else {
    console.log('Sorry, the item is not available :(');
}

Isto resulta em:

Sorry, the item is not available :(

Usando filter() com map()

O método map() é usado para percorrer um array e aplicar uma função a cada elemento, retornando o resultado para um novo array.

É um método muito comum, e combina muito bem com o filter().

Por exemplo, vamos filtrar alguns alunos e mapear os elementos para seus nomes e sobrenomes:

const students = [
    {firstName: "John", lastName: "Doe", grduationYear: 2022},
    {firstName: "Stephen", lastName: "Matt", grduationYear: 2023},
    {firstName: "Abigail", lastName: "Susu", grduationYear: 2022}
];

let graduatingStudents = students
    .filter((element) => element.grduationYear === new Date().getFullYear())
    .map((item) => {
        return `${item.firstName} ${item.lastName}`;
    });

console.log(graduatingStudents); // ["John Doe", "Abigail Susu"]

Usando filter() com indexOf()

O método indexOf() pode ser usado para verificar se uma string começa com uma substring e retornar elementos condicionalmente com base nisso.

Por exemplo, poderíamos filtrar uma lista de cursos de ciências, com base em se eles começam com mth, significando que são cursos de matemática:

let sciCourses = ["Mth101", "Chm201", "Bio301", "Mth203", "Mth205"];

function checkCourses(courseArray, searchText) {
    return courseArray.filter(function (item) {
        return item.toLowerCase().indexOf(searchText.toLowerCase()) !== -1;
    });
}

console.log(checkCourses(sciCourses, "mth")); // ["Mth101", "Mth203", "Mth205"]

Novamente, o método filter() não altera o array original, precisamos salvar o array filtrado para trabalhar com ele mais tarde.

Conclusão

Neste guia, examinamos como o método filter() do JavaScript funciona e como podemos usá-lo para filtrar elementos de uma matriz, considerando um predicado/certos critérios de filtragem.

Demos uma olhada nos argumentos que acompanham, como context, index e array que permitem alterar a lógica do predicado.

Por fim, examinamos vários exemplos e abordamos como o find() é uma alternativa para quando você está procurando apenas por um único elemento e como filter() pode ser usado com outros métodos em uma cadeia.

Obrigado por visitar o blog e por ler esse artigo, se tive qualquer dúvida, ideia ou sugestão, não hesite em entrar em contato pelo meu e-mail: lindomar@covildodev.com.br