Dominando a Busca, Filtragem e Transformação de Dados

Você já aprendeu a criar arrays e manipulá-los com métodos básicos como push, pop, shift e unshift. Agora é hora de dar o próximo passo! Nesta aula, você descobrirá métodos poderosos que transformarão a maneira como você trabalha com listas de dados.

Imagine ter uma lista com centenas de produtos e precisar encontrar apenas aqueles que custam menos de R$ 100. Ou transformar uma lista de nomes para que todos fiquem em letras maiúsculas. Os métodos que aprenderemos hoje tornam essas tarefas simples e elegantes!

Buscando Elementos: includes(), indexOf() e find()

1.1 O Método includes()

O includes() é o método mais simples para verificar se um elemento existe no array. Ele retorna true se o elemento for encontrado e false caso contrário.

Sintaxe:

array.includes(elemento)

Exemplo Prático:

let frutas = ["maçã", "banana", "uva", "laranja"];

console.log(frutas.includes("banana")); // true
console.log(frutas.includes("morango")); // false

Quando usar: Sempre que você precisar apenas saber SE um elemento existe, sem se importar com sua posição.

Caso Real:

let produtosNoCarrinho = ["notebook", "mouse", "teclado"];

if (produtosNoCarrinho.includes("mouse")) {
    console.log("O mouse já está no carrinho!");
} else {
    console.log("Adicione o mouse ao carrinho.");
}

1.2 O Método indexOf()

Enquanto o includes() apenas verifica existência, o indexOf() nos diz ONDE o elemento está. Ele retorna o índice (posição) do primeiro elemento encontrado, ou -1 se não encontrar nada.

Sintaxe:

array.indexOf(elemento)

Por que retorna -1? Esta é uma convenção clássica em programação para indicar "não encontrado", já que índices válidos começam em 0.

Exemplo Prático:

let animais = ["gato", "cachorro", "pássaro", "cachorro"];

console.log(animais.indexOf("cachorro")); // 1 (primeira ocorrência)
console.log(animais.indexOf("peixe"));    // -1 (não encontrado)

Diferença importante: O indexOf() retorna apenas a posição da PRIMEIRA ocorrência.

Caso Real:

let tarefas = ["estudar", "exercitar", "ler", "programar"];
let posicao = tarefas.indexOf("exercitar");

if (posicao !== -1) {
    console.log(`A tarefa está na posição ${posicao}`);
    tarefas[posicao] = "exercitar ✓"; // Marcar como concluída
}

1.3 O Método find()

O find() é o mais poderoso dos três. Ele procura o primeiro elemento que satisfaz uma condição (não apenas igualdade exata). Retorna o elemento encontrado ou undefined se nenhum satisfizer a condição.

Sintaxe:

array.find(funcao)

Exemplo Prático:

let numeros = [5, 12, 8, 130, 44];

// Encontrar o primeiro número maior que 10
let resultado = numeros.find(numero => numero > 10);
console.log(resultado); // 12

Buscando em Arrays de Objetos:

let usuarios = [
    {id: 1, nome: "Ana", idade: 25},
    {id: 2, nome: "Bruno", idade: 30},
    {id: 3, nome: "Carla", idade: 22}
];

// Encontrar usuário com id específico
let usuario = usuarios.find(u => u.id === 2);
console.log(usuario.nome); // "Bruno"

// Encontrar primeiro usuário maior de idade
let adulto = usuarios.find(u => u.idade >= 18);
console.log(adulto.nome); // "Ana"

Quando usar: Quando você precisa buscar baseado em uma condição mais complexa que simples igualdade.

Filtrando Dados: O Método filter()

2.1 Conceito Fundamental

Enquanto o find() retorna apenas o PRIMEIRO elemento que satisfaz a condição, o filter() retorna TODOS os elementos que atendem ao critério. Ele cria um novo array com os elementos filtrados.

Princípio: Filtrar significa "separar o que queremos do que não queremos".

Sintaxe:

array.filter(funcao)

2.2 Exemplos Práticos

Filtrando Números:

let numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Apenas números pares
let pares = numeros.filter(n => n % 2 === 0);
console.log(pares); // [2, 4, 6, 8, 10]

// Números maiores que 5
let maioresQue5 = numeros.filter(n => n > 5);
console.log(maioresQue5); // [6, 7, 8, 9, 10]

Filtrando Objetos:

let produtos = [
    {nome: "Notebook", preco: 3000, categoria: "eletrônicos"},
    {nome: "Mouse", preco: 50, categoria: "eletrônicos"},
    {nome: "Livro", preco: 40, categoria: "livros"},
    {nome: "Teclado", preco: 150, categoria: "eletrônicos"}
];

// Produtos baratos (menos de R$ 100)
let baratos = produtos.filter(p => p.preco < 100);
console.log(baratos);
// [{nome: "Mouse"...}, {nome: "Livro"...}]

// Apenas eletrônicos
let eletronicos = produtos.filter(p => p.categoria === "eletrônicos");
console.log(eletronicos.length); // 3

Filtrando Strings:

let palavras = ["JavaScript", "Python", "Java", "Ruby", "PHP"];

// Palavras com mais de 4 letras
let longas = palavras.filter(palavra => palavra.length > 4);
console.log(longas); // ["JavaScript", "Python"]

// Palavras que contêm "Java"
let comJava = palavras.filter(palavra => palavra.includes("Java"));
console.log(comJava); // ["JavaScript", "Java"]

2.3 Características Importantes

  1. Não modifica o array original - Sempre retorna um novo array
  2. Pode retornar array vazio - Se nenhum elemento satisfizer a condição
  3. Mantém a ordem - Os elementos filtrados aparecem na mesma ordem do array original
let idades = [15, 22, 18, 30, 12, 25];
let maioresDeIdade = idades.filter(idade => idade >= 18);

console.log(idades);          // [15, 22, 18, 30, 12, 25] - não mudou
console.log(maioresDeIdade);  // [22, 18, 30, 25] - novo array

Transformando Dados: O Método map()

3.1 Conceito de Transformação

O map() é um dos métodos mais poderosos e utilizados. Ele aplica uma função a CADA elemento do array e retorna um NOVO array com os resultados transformados.

Princípio: Transformar significa "pegar cada elemento e convertê-lo em algo novo".

Sintaxe:

array.map(funcao)

3.2 Exemplos Práticos

Transformando Números:

let numeros = [1, 2, 3, 4, 5];

// Dobrar cada número
let dobrados = numeros.map(n => n * 2);
console.log(dobrados); // [2, 4, 6, 8, 10]

// Elevar ao quadrado
let quadrados = numeros.map(n => n * n);
console.log(quadrados); // [1, 4, 9, 16, 25]

// Converter para strings
let strings = numeros.map(n => `Número ${n}`);
console.log(strings); // ["Número 1", "Número 2", ...]

Transformando Objetos:

let pessoas = [
    {nome: "Ana", idade: 25},
    {nome: "Bruno", idade: 30},
    {nome: "Carla", idade: 22}
];

// Extrair apenas os nomes
let nomes = pessoas.map(pessoa => pessoa.nome);
console.log(nomes); // ["Ana", "Bruno", "Carla"]

// Criar saudações personalizadas
let saudacoes = pessoas.map(pessoa => `Olá, ${pessoa.nome}!`);
console.log(saudacoes);
// ["Olá, Ana!", "Olá, Bruno!", "Olá, Carla!"]

// Adicionar nova propriedade
let pessoasComCategoria = pessoas.map(pessoa => ({
    ...pessoa,
    categoria: pessoa.idade >= 25 ? "adulto" : "jovem"
}));
console.log(pessoasComCategoria);

Transformando Strings:

let nomes = ["ana", "bruno", "carla"];

// Primeira letra maiúscula
let capitalizados = nomes.map(nome => 
    nome.charAt(0).toUpperCase() + nome.slice(1)
);
console.log(capitalizados); // ["Ana", "Bruno", "Carla"]

3.3 Características Importantes

  1. Sempre retorna array do mesmo tamanho - Se entrar 5 elementos, sai 5 elementos
  2. Não modifica o array original
  3. Pode transformar tipos - Entrar números, sair strings
let precos = [10, 20, 30];

// Array original não muda
let precosComDesconto = precos.map(p => p * 0.9);

console.log(precos);            // [10, 20, 30]
console.log(precosComDesconto); // [9, 18, 27]

Verificação: some() e every()

4.1 O Método some()

O some() verifica se PELO MENOS UM elemento satisfaz a condição. Retorna true ou false.

Sintaxe:

array.some(funcao)

Exemplos:

let numeros = [1, 3, 5, 8, 9];

// Existe algum número par?
console.log(numeros.some(n => n % 2 === 0)); // true (8 é par)

// Existe algum número negativo?
console.log(numeros.some(n => n < 0)); // false

let produtos = [
    {nome: "Mouse", preco: 50},
    {nome: "Teclado", preco: 150},
    {nome: "Monitor", preco: 800}
];

// Existe algum produto barato (menos de R$ 100)?
console.log(produtos.some(p => p.preco < 100)); // true

4.2 O Método every()

O every() verifica se TODOS os elementos satisfazem a condição. Retorna true ou false.

Sintaxe:

array.every(funcao)

Exemplos:

let idades = [20, 25, 30, 35];

// Todos são maiores de idade?
console.log(idades.every(idade => idade >= 18)); // true

// Todos são maiores de 25?
console.log(idades.every(idade => idade > 25)); // false

let notas = [7, 8, 6, 9];

// Todos foram aprovados (nota >= 6)?
console.log(notas.every(nota => nota >= 6)); // true

4.3 Diferença Conceitual

  • some(): "Existe PELO MENOS UM?"
  • every(): "São TODOS?"
let numeros = [2, 4, 6, 8, 10];

console.log(numeros.some(n => n > 5));  // true (existe algum)
console.log(numeros.every(n => n > 5)); // false (não são todos)

console.log(numeros.some(n => n % 2 === 0));  // true
console.log(numeros.every(n => n % 2 === 0)); // true (todos são pares)

Ordenação: O Método sort()

5.1 Ordenação Básica

O sort() ordena os elementos do array. ATENÇÃO: Ele modifica o array original!

Sintaxe:

array.sort()
array.sort(funcaoDeComparacao)

5.2 O Problema da Ordenação Padrão

Por padrão, o sort() converte elementos para strings e compara lexicograficamente (como em um dicionário). Isso causa resultados inesperados com números!

let numeros = [10, 5, 40, 25, 1000, 1];

// Ordenação padrão (ERRADA para números!)
numeros.sort();
console.log(numeros); // [1, 10, 1000, 25, 40, 5] 😱
// Ordena como texto: "1" < "10" < "1000" < "25"...

5.3 Ordenação Numérica Correta

Para ordenar números, precisamos fornecer uma função de comparação:

let numeros = [10, 5, 40, 25, 1000, 1];

// Ordem crescente
numeros.sort((a, b) => a - b);
console.log(numeros); // [1, 5, 10, 25, 40, 1000] ✓

// Ordem decrescente
numeros.sort((a, b) => b - a);
console.log(numeros); // [1000, 40, 25, 10, 5, 1] ✓

Como funciona:

  • Se a - b for negativo, a vem antes de b
  • Se a - b for positivo, b vem antes de a
  • Se for zero, mantém a ordem

5.4 Ordenando Strings

Para strings, a ordenação padrão funciona bem:

let frutas = ["banana", "maçã", "uva", "abacaxi"];

frutas.sort();
console.log(frutas); // ["abacaxi", "banana", "maçã", "uva"]

// Ordem inversa
frutas.sort().reverse();
console.log(frutas); // ["uva", "maçã", "banana", "abacaxi"]

5.5 Ordenando Objetos

let produtos = [
    {nome: "Mouse", preco: 50},
    {nome: "Teclado", preco: 150},
    {nome: "Monitor", preco: 800}
];

// Ordenar por preço (crescente)
produtos.sort((a, b) => a.preco - b.preco);
console.log(produtos);

// Ordenar por nome (alfabética)
produtos.sort((a, b) => a.nome.localeCompare(b.nome));
console.log(produtos);

Combinando Métodos (Encadeamento)

Uma das características mais poderosas é a possibilidade de encadear métodos, aplicando múltiplas operações em sequência!

6.1 Exemplos de Encadeamento

let numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Filtrar pares, dobrar valores, somar tudo
let resultado = numeros
    .filter(n => n % 2 === 0)    // [2, 4, 6, 8, 10]
    .map(n => n * 2);              // [4, 8, 12, 16, 20]

console.log(resultado);

Exemplo Real - Sistema de Produtos:

let produtos = [
    {nome: "Notebook", preco: 3000, estoque: 5},
    {nome: "Mouse", preco: 50, estoque: 0},
    {nome: "Teclado", preco: 150, estoque: 10},
    {nome: "Monitor", preco: 800, estoque: 3}
];

// Encontrar produtos disponíveis, ordenar por preço e formatar
let produtosFormatados = produtos
    .filter(p => p.estoque > 0)           // Apenas disponíveis
    .sort((a, b) => a.preco - b.preco)    // Ordenar por preço
    .map(p => `${p.nome}: R$ ${p.preco}`); // Formatar

console.log(produtosFormatados);
// ["Mouse: R$ 50", "Teclado: R$ 150", "Monitor: R$ 800", "Notebook: R$ 3000"]

Casos de Uso Práticos

7.1 Sistema de Busca de Produtos

let produtos = [
    {id: 1, nome: "Notebook Dell", preco: 3000, categoria: "eletrônicos"},
    {id: 2, nome: "Mouse Logitech", preco: 50, categoria: "eletrônicos"},
    {id: 3, nome: "Livro JavaScript", preco: 40, categoria: "livros"},
    {id: 4, nome: "Teclado Mecânico", preco: 300, categoria: "eletrônicos"}
];

function buscarProdutos(termo, precoMaximo) {
    return produtos
        .filter(p => p.nome.toLowerCase().includes(termo.toLowerCase()))
        .filter(p => p.preco <= precoMaximo)
        .sort((a, b) => a.preco - b.preco);
}

console.log(buscarProdutos("mouse", 100));
// [{id: 2, nome: "Mouse Logitech", preco: 50, ...}]

7.2 Análise de Notas de Alunos

let alunos = [
    {nome: "Ana", nota: 8.5},
    {nome: "Bruno", nota: 6.0},
    {nome: "Carla", nota: 9.0},
    {nome: "Diego", nota: 5.5},
    {nome: "Elena", nota: 7.5}
];

// Alunos aprovados (nota >= 6)
let aprovados = alunos.filter(a => a.nota >= 6);
console.log(`${aprovados.length} alunos aprovados`);

// Todos foram aprovados?
let todosAprovados = alunos.every(a => a.nota >= 6);
console.log(`Todos aprovados: ${todosAprovados}`);

// Alguém tirou nota máxima?
let temNotaMaxima = alunos.some(a => a.nota === 10);
console.log(`Tem nota 10: ${temNotaMaxima}`);

// Nomes dos aprovados em ordem alfabética
let nomesAprovados = alunos
    .filter(a => a.nota >= 6)
    .map(a => a.nome)
    .sort();
console.log(nomesAprovados);

7.3 Processamento de Dados de Vendas

let vendas = [
    {produto: "Mouse", quantidade: 5, precoUnitario: 50},
    {produto: "Teclado", quantidade: 3, precoUnitario: 150},
    {produto: "Monitor", quantidade: 2, precoUnitario: 800}
];

// Calcular valor total de cada venda
let vendasComTotal = vendas.map(v => ({
    ...v,
    total: v.quantidade * v.precoUnitario
}));

console.log(vendasComTotal);

// Vendas acima de R$ 400
let vendasGrandes = vendasComTotal.filter(v => v.total > 400);
console.log(vendasGrandes);

Comparação entre Métodos

| Método | Retorna | Modifica Original? | Quando Usar | |--------|---------|-------------------|-------------| | includes() | Boolean | Não | Verificar se elemento existe | | indexOf() | Number (índice) | Não | Encontrar posição de elemento | | find() | Elemento ou undefined | Não | Buscar primeiro elemento que atende condição | | filter() | Array | Não | Obter todos os elementos que atendem condição | | map() | Array | Não | Transformar todos os elementos | | some() | Boolean | Não | Verificar se ALGUM elemento atende condição | | every() | Boolean | Não | Verificar se TODOS os elementos atendem condição | | sort() | Array | SIM | Ordenar elementos |

Conceitos Importantes para Fixar

9.1 Imutabilidade

A maioria desses métodos não modifica o array original. Eles criam e retornam um novo array:

let original = [1, 2, 3];
let dobrado = original.map(n => n * 2);

console.log(original); // [1, 2, 3] - não mudou!
console.log(dobrado);  // [2, 4, 6]

Exceção: O sort() modifica o array original!

9.2 Funções de Callback

Todos esses métodos recebem uma função como argumento. Essa função é chamada para cada elemento do array:

array.map(function(elemento, indice, arrayCompleto) {
    // Esta função é executada para cada elemento
    return elemento; // Retorna o valor transformado
});

// Forma mais comum com arrow function
array.map(elemento => elemento * 2);

9.3 Programação Funcional

Esses métodos representam um paradigma de programação chamado programação funcional, onde:

  • Trabalhamos com transformações de dados
  • Evitamos modificar dados existentes
  • Componemos operações simples para criar soluções complexas

Próximos Passos

Na próxima aula nos aprofundaremos nos objetos. Você vai aprender:

  • Novas formas de criar e acessar propriedades de objetos
  • Como alterar, adicionar e deletar propriedades
  • Percorrer todas as propriedades dde um objeto
  • Criar objetos dentro de objetos

Lembre-se: A prática leva à perfeição. Quanto mais você usar esses métodos, mais natural se tornará identificar qual usar em cada situação!