SkillsTecnológicas
Menu
Conteúdo da trilha

Busca e agregação de valores em vetores

Aprenda a buscar, contar, somar e comparar valores em vetores, escolhendo o estado correto e tratando ausência, duplicados e coleções vazias.

Conteúdo 42 de 52

Coleção desenhada a lápis se divide entre uma lupa que encontra um elemento e um funil que combina todos em um resultado

A pergunta determina o que o percurso precisa conservar

Depois de aprender como percorrer um vetor, você pode usar cada visita para responder perguntas sobre a coleção. Duas famílias aparecem com frequência:

  • busca: existe um valor? Em qual posição aparece? Qual é a primeira ocorrência?
  • agregação: quantos atendem à regra? Qual é a soma, a média, o menor ou o maior valor?

O laço pode ser parecido, mas o estado preservado e a condição de término mudam. Uma busca pela primeira ocorrência pode terminar assim que encontra a resposta. Uma soma precisa incorporar todos os valores que pertencem ao resultado.

Use este vetor de estoque diário como exemplo:

estoques = [12, 0, 7, 12, 3]

Antes de programar, transforme a pergunta em um contrato:

PerguntaEstado necessárioPode parar antes do fim?Resultado sem correspondência
existe estoque igual a 7?indicador lógicosimfalso
onde aparece o primeiro 12?posição ou ausênciasimausência
quantas posições têm estoque positivo?contadornão0
qual é o total em estoque?soma parcialnão0
qual é o maior estoque?candidato existente ou ausêncianãoausência
Mapa relaciona busca por existência a um indicador e parada antecipada, busca por posição a um índice ou ausência, e agregações a contador, total ou candidato com percurso completo
Escolher o estado pela pergunta evita usar uma variável que não consegue representar todas as respostas possíveis.

Para buscar, compare cada item e represente a ausência

A busca linear examina elementos em sequência até encontrar a correspondência ou terminar a coleção. Para localizar a primeira posição cujo valor é 12:

alvo <- 12
posicaoEncontrada <- AUSENTE

PARA indice <- 0; indice < tamanho(estoques); indice <- indice + 1 FAÇA
  SE estoques[indice] = alvo ENTÃO
    posicaoEncontrada <- indice
    INTERROMPER
  FIM SE
FIM PARA

O estado começa como AUSENTE porque ainda não existe evidência de correspondência. Quando encontra o alvo, recebe um índice válido e o laço termina. Depois, há duas possibilidades explícitas:

SE posicaoEncontrada está AUSENTE ENTÃO
  EXIBIR "valor não encontrado"
SENÃO
  EXIBIR "primeira posição:", posicaoEncontrada
FIM SE

Algumas linguagens ou APIs usam -1, null, None, uma opção ou outro contrato para representar ausência. O importante é não confundir “não encontrado” com uma posição válida. Como o índice 0 é válido, testar apenas SE posicaoEncontrada pode classificar a primeira posição como se fosse ausência em linguagens que tratam zero como falso.

Existência, posição e valor encontrado são resultados diferentes

Se a pergunta é apenas “existe?”, um indicador basta:

const estoques = [12, 0, 7, 12, 3];
const alvo = 7;
let encontrado = false;

for (const estoque of estoques) {
  if (estoque === alvo) {
    encontrado = true;
    break;
  }
}

console.log(encontrado); // true

Se a posição importa, percorra com índice:

let posicaoEncontrada = -1;

for (let indice = 0; indice < estoques.length; indice += 1) {
  if (estoques[indice] === alvo) {
    posicaoEncontrada = indice;
    break;
  }
}

console.log(posicaoEncontrada); // 2

Retornar somente o valor encontrado não responde onde ele estava. Retornar somente true não distingue a primeira da última ocorrência. Defina o formato da saída antes de escolher a variável.

Na busca pelo valor 7, o percurso visita 12, zero e 7 e para; na soma, o percurso visita os cinco valores até o fim e produz 34
A busca pela primeira resposta pode usar curto-circuito; uma agregação que depende de todos os itens não pode ignorar o restante.

No exemplo, a busca visita três posições para encontrar 7. Se o alvo fosse 3 ou estivesse ausente, seriam necessárias cinco comparações. Em uma coleção não ordenada, não encontrar nas primeiras posições não permite concluir que o valor não está depois.

Decida se deseja a primeira ocorrência ou todas

O vetor possui 12 nos índices 0 e 3. O comando INTERROMPER define que a resposta será a primeira ocorrência.

Para contar todas as ocorrências, não interrompa:

quantidade <- 0

PARA CADA estoque EM estoques FAÇA
  SE estoque = 12 ENTÃO
    quantidade <- quantidade + 1
  FIM SE
FIM PARA

Resultado: 2.

Para guardar todas as posições, a saída deixa de ser um único índice e passa a ser outra coleção:

const posicoes = [];

for (let indice = 0; indice < estoques.length; indice += 1) {
  if (estoques[indice] === 12) {
    posicoes.push(indice);
  }
}

console.log(posicoes); // [0, 3]

“Primeiro”, “último”, “qualquer” e “todos” não são detalhes de implementação. São contratos diferentes e podem exigir término e saída diferentes.

Para agregar, preserve um resultado parcial

Uma agregação transforma vários elementos em um resultado. A cada passagem, o estado representa a resposta para os itens já processados.

Para somar o estoque:

total <- 0

PARA CADA estoque EM estoques FAÇA
  total <- total + estoque
FIM PARA

Rastreamento:

Valor atualtotal antestotal depois
12012
01212
71219
121931
33134

O zero inicial é adequado porque a soma de uma coleção vazia pode ser definida como zero e 0 + valor preserva o primeiro valor. A aula sobre contadores e acumuladores explica por que outras operações exigem valores iniciais diferentes.

Para contar apenas estoques positivos, a atualização depende de uma condição:

let quantidadePositivos = 0;

for (const estoque of estoques) {
  if (estoque > 0) {
    quantidadePositivos += 1;
  }
}

console.log(quantidadePositivos); // 4

A posição 0 contém o valor 12; já o valor 0 está na posição 1. Separar índice e valor continua essencial.

Média exige soma e quantidade sob o mesmo critério

Para calcular a média somente dos estoques positivos, some e conte exatamente os mesmos itens:

let totalPositivo = 0;
let quantidadePositivos = 0;

for (const estoque of estoques) {
  if (estoque > 0) {
    totalPositivo += estoque;
    quantidadePositivos += 1;
  }
}

const mediaPositiva = quantidadePositivos > 0
  ? totalPositivo / quantidadePositivos
  : null;

console.log(mediaPositiva); // 8.5

Dividir pelo tamanho total produziria 34 / 5 = 6,8, que responde outra pergunta: a média incluindo o estoque zero. Nenhuma fórmula está isoladamente errada; o critério de inclusão precisa ser coerente com a pergunta.

O caso vazio ou sem valores válidos precisa de uma decisão explícita. Retornar null, exibir uma mensagem, lançar um erro ou usar outro tipo de ausência depende do contrato. Dividir por zero não é uma resposta para “não há itens”.

Mínimo e máximo precisam começar com um valor real

Inicializar maior com zero falha em [-8, -3, -11]: o algoritmo devolveria 0, embora zero não esteja na coleção. Para uma coleção não vazia, use o primeiro elemento como candidato e percorra a partir do segundo:

function encontrarMaior(valores) {
  if (valores.length === 0) {
    return null;
  }

  let maior = valores[0];

  for (let indice = 1; indice < valores.length; indice += 1) {
    if (valores[indice] > maior) {
      maior = valores[indice];
    }
  }

  return maior;
}
O candidato a maior começa em menos 8, muda para menos 3 e permanece em menos 3 quando o valor menos 11 é processado
O candidato sempre pertence à parte já processada; assim, valores negativos não exigem um sentinela numérico inventado.

Para obter também a posição do maior, preserve valor e índice juntos:

let maiorValor = estoques[0];
let indiceDoMaior = 0;

for (let indice = 1; indice < estoques.length; indice += 1) {
  if (estoques[indice] > maiorValor) {
    maiorValor = estoques[indice];
    indiceDoMaior = indice;
  }
}

Com > o empate mantém a primeira ocorrência do maior. Usar >= atualizaria também nos empates e terminaria com a última. Essa escolha deve ser intencional.

Combine agregações quando o critério for compatível

Um único percurso pode calcular quantidade, soma, mínimo e máximo:

function resumir(valores) {
  if (valores.length === 0) {
    return null;
  }

  let total = 0;
  let menor = valores[0];
  let maior = valores[0];

  for (const valor of valores) {
    total += valor;

    if (valor < menor) menor = valor;
    if (valor > maior) maior = valor;
  }

  return {
    quantidade: valores.length,
    total,
    media: total / valores.length,
    menor,
    maior,
  };
}

Combinar reduz passagens, mas aumenta a quantidade de estado que precisa ser verificada. Faça isso quando as operações usam a mesma coleção e o mesmo critério de inclusão. Se “total” considera todos os itens e “maior válido” ignora negativos, nomes e condições devem tornar essa diferença visível.

Não interrompa o laço ao encontrar um valor grande se ainda precisa provar que ele é o máximo. Sem uma garantia adicional sobre os dados, uma posição posterior pode conter um valor maior.

Métodos prontos preservam os mesmos contratos

JavaScript oferece métodos que expressam intenções comuns:

const primeiroPositivo = estoques.find((valor) => valor > 0);
const total = estoques.reduce((parcial, valor) => parcial + valor, 0);

find() devolve o primeiro elemento que satisfaz o teste e produz undefined quando nenhum satisfaz. reduce() passa um resultado parcial para a próxima chamada; fornecer 0 torna explícito o estado inicial da soma e trata o array vazio.

Python possui operações equivalentes para casos usuais:

estoques = [12, 0, 7, 12, 3]

total = sum(estoques)
maior = max(estoques, default=None)

Em C#, LINQ também oferece operações de agregação e seleção. Esses recursos reduzem código, mas não decidem por você:

  • se a resposta deve ser valor, posição ou indicador;
  • qual critério inclui um item;
  • o que uma coleção vazia significa;
  • se empates conservam a primeira ou a última ocorrência;
  • se parar na primeira correspondência é permitido.

Prefira o laço explícito durante a aprendizagem e quando ele torna uma regra particular mais clara. Use a API da linguagem quando seu contrato conhecido corresponde exatamente ao problema.

Diagnostique o erro pelo contrato quebrado

A busca informa ausência quando o alvo está no índice zero

Provavelmente a posição foi usada como valor lógico. Compare explicitamente com o marcador de ausência.

A busca pela primeira ocorrência devolve a última

O algoritmo continuou atualizando a posição depois de encontrar. Interrompa na primeira ou registre que deseja a última.

A soma contém apenas o último item

O total pode ter sido reinicializado dentro do laço ou substituído por total = valor, em vez de incorporar o estado anterior.

A média usa denominador incompatível

Confira se contador e soma são atualizados dentro da mesma condição.

O maior não pertence à coleção

Um sentinela numérico, como zero, entrou no resultado. Use o primeiro item real ou represente ausência.

O algoritmo para cedo demais

Curto-circuito é correto para a primeira correspondência, mas normalmente incorreto para soma, contagem total, mínimo e máximo. Relacione o término à resposta prometida e às condições de parada.

Teste ausência, duplicidade e fronteiras

Faça um teste de mesa com casos que exercitam contratos diferentes:

CasoO que verifica
[]resultado de coleção vazia
[7], alvo 7correspondência no primeiro e único índice
[7, 2, 7], alvo 7primeira ocorrência versus todas
[2, 4, 7], alvo 7correspondência no último índice
[2, 4, 6], alvo 7ausência após percurso completo
[-8, -3, -11]máximo sem sentinela zero
[0, 0]diferença entre zero válido e ausência

Para agregações combinadas, confira cada resultado separadamente antes de confiar no objeto final.

Pratique com lotes de entrega

Considere os tempos em minutos:

tempos = [32, 18, 45, 18, 27]

Antes de escrever o código, defina saída, estado inicial, atualização e término para:

  1. verificar se existe uma entrega de 45 minutos;
  2. encontrar a primeira posição com 18 minutos;
  3. guardar todas as posições com 18 minutos;
  4. calcular quantidade, total e média;
  5. encontrar menor e maior tempo, preservando a primeira posição em caso de empate;
  6. explicar quais operações podem parar cedo;
  7. testar também [], [18] e [-5, -2] quando negativos forem aceitos.

O exercício está completo quando cada resultado possui um contrato de ausência e você consegue justificar por que o laço percorre parte ou toda a coleção.

O que você deve guardar

Busca e agregação podem usar o mesmo percurso, mas respondem perguntas diferentes. A busca preserva um indicador, valor ou posição e pode parar na primeira correspondência quando esse é o contrato. A agregação conserva um resultado parcial e normalmente precisa processar todos os itens relevantes.

Inicialize soma e contagem com zero; derive mínimo e máximo de um elemento real ou represente ausência; use o mesmo critério para soma e quantidade de uma média; e decida conscientemente como tratar vazio, duplicados e empates. Com esses padrões, você já consegue resumir coleções lineares e está preparado para aprender como matrizes organizam dados em mais de uma dimensão.

Referências