Pular para o conteúdo

A primeira escola especializada em tecnologia do Alto Solimões, com corpo técnico formado na área.

Módulo 3: Repetição e dados

map, filter e reduce

Transformar listas sem escrever laço

map: transformar cada item

const precosEmCentavos = [1250, 2500, 800];

const emReais = precosEmCentavos.map((centavos) => centavos / 100);
console.log(emReais); // → [12.5, 25, 8]
console.log(precosEmCentavos); // → [1250, 2500, 800] ← intacto

Mesmo tamanho, cada item transformado.

Com objetos:

const produtos = [
{ nome: "Farinha", precoEmCentavos: 1250 },
{ nome: "Açaí", precoEmCentavos: 2500 },
];

const nomes = produtos.map((p) => p.nome);
console.log(nomes); // → ["Farinha", "Açaí"]

const etiquetas = produtos.map((p) => `${p.nome}: R$ ${(p.precoEmCentavos / 100).toFixed(2)}`);
console.log(etiquetas); // → ["Farinha: R$ 12.50", "Açaí: R$ 25.00"]

filter: escolher

const precos = [1250, 2500, 800, 3000];

const baratos = precos.filter((preco) => preco < 2000);
console.log(baratos); // → [1250, 800]

Menos itens (ou nenhum), nunca mais. A função passada devolve true para manter e false para descartar.

const alunos = [
{ nome: "Ana", idade: 15, matriculado: true },
{ nome: "João", idade: 20, matriculado: false },
{ nome: "Maria", idade: 17, matriculado: true },
];

const matriculados = alunos.filter((a) => a.matriculado);
const menores = alunos.filter((a) => a.idade < 18);
const ambos = alunos.filter((a) => a.matriculado && a.idade < 18);

reduce: juntar tudo num valor

const precos = [1250, 2500, 800];

const total = precos.reduce((soma, preco) => soma + preco, 0);
console.log(total); // → 4550

Dois argumentos:

  1. a função, que recebe o acumulado até agora e o item atual;
  2. o valor inicial: aqui, 0.

Passo a passo:

início:  soma = 0
item 1:  soma = 0 + 1250    = 1250
item 2:  soma = 1250 + 2500 = 3750
item 3:  soma = 3750 + 800  = 4550

Com objetos:

const carrinho = [
{ produto: "Farinha", quilos: 3, precoPorKgEmCentavos: 1250 },
{ produto: "Açaí", quilos: 2, precoPorKgEmCentavos: 2500 },
];

const total = carrinho.reduce((soma, item) => {
return soma + Math.round(item.precoPorKgEmCentavos * item.quilos);
}, 0);

console.log(`R$ ${(total / 100).toFixed(2)}`); // → R$ 87.50

E reduce não devolve só número. Agrupar, por exemplo:

const alunos = [
{ nome: "Ana", turno: "manha" },
{ nome: "João", turno: "tarde" },
{ nome: "Maria", turno: "manha" },
];

const porTurno = alunos.reduce((grupos, aluno) => {
const atual = grupos[aluno.turno] ?? [];
return { ...grupos, [aluno.turno]: [...atual, aluno.nome] };
}, {});

console.log(porTurno);
// → { manha: ["Ana", "Maria"], tarde: ["João"] }

Encadear

O resultado de um é a entrada do seguinte:

const produtos = [
{ nome: "Farinha", precoEmCentavos: 1250, disponivel: true },
{ nome: "Açaí", precoEmCentavos: 2500, disponivel: true },
{ nome: "Tucumã", precoEmCentavos: 800, disponivel: false },
{ nome: "Cupuaçu", precoEmCentavos: 1800, disponivel: true },
];

const totalDisponivel = produtos
.filter((p) => p.disponivel)
.map((p) => p.precoEmCentavos)
.reduce((soma, preco) => soma + preco, 0);

console.log(`R$ ${(totalDisponivel / 100).toFixed(2)}`); // → R$ 55.50

Lê-se de cima para baixo: filtre os disponíveis, pegue os preços, some.

Compare com o for equivalente:

let total = 0;
for (const p of produtos) {
if (p.disponivel) {
total += p.precoEmCentavos;
}
}

O for não é errado. A diferença é que na versão encadeada o nome do método já conta a intenção: você lê filter e sabe que ali se escolhe, sem precisar ler o corpo.

Os primos

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

numeros.forEach((n) => console.log(n)); // percorre, não devolve nada
numeros.find((n) => n > 3); // → 4, o primeiro
numeros.findIndex((n) => n > 3); // → 3, a posição
numeros.some((n) => n > 4); // → true, algum
numeros.every((n) => n > 0); // → true, todos
numeros.flat(); // achata listas aninhadas

forEach é o for em forma de método: percorre e não devolve nada. Se você está usando forEach para montar outra lista, o que você quer é map.

A lista da feira, do começo ao fim

const FEIRA = [
{ produto: "Farinha d'água", categoria: "farinha", precoEmCentavos: 1250, estoqueEmKg: 40 },
{ produto: "Farinha seca", categoria: "farinha", precoEmCentavos: 1100, estoqueEmKg: 0 },
{ produto: "Açaí", categoria: "fruta", precoEmCentavos: 2500, estoqueEmKg: 15 },
{ produto: "Tucumã", categoria: "fruta", precoEmCentavos: 800, estoqueEmKg: 22 },
{ produto: "Cupuaçu", categoria: "fruta", precoEmCentavos: 1800, estoqueEmKg: 8 },
];

const emEstoque = FEIRA.filter((item) => item.estoqueEmKg > 0);

console.log(`${emEstoque.length} de ${FEIRA.length} produtos disponíveis`);

const frutas = emEstoque
.filter((item) => item.categoria === "fruta")
.map((item) => `${item.produto} - R$ ${(item.precoEmCentavos / 100).toFixed(2)}/kg`);

console.log(frutas.join("\n"));

const valorDoEstoque = emEstoque.reduce(
(soma, item) => soma + item.precoEmCentavos * item.estoqueEmKg,
0
);

console.log(`Valor total: R$ ${(valorDoEstoque / 100).toFixed(2)}`);

const maisCaro = emEstoque.reduce((maior, item) =>
item.precoEmCentavos > maior.precoEmCentavos ? item : maior
);

console.log(`Mais caro: ${maisCaro.produto}`);

Exercícios

  1. Com map, transforme uma lista de preços em centavos numa de reais.
  2. Com filter, pegue só os alunos maiores de idade.
  3. Com reduce, some o total de uma compra.
  4. Encadeie os três: filtre os disponíveis, pegue os preços e some.
  5. Com reduce, agrupe alunos por turno.
  6. Com reduce, encontre o produto mais caro.
  7. Reescreva um for que você tenha escrito antes usando filter e reduce.

Referências

Testa o que você leu

5 perguntas sobre esta aula. Errar aqui não custa nada - a explicação vem junto da correção.

Pergunta 1 de 5
O que `map` devolve?