SkillsTecnológicas
Menu
Conteúdo da trilha

Estruturas de repetição aninhadas

Combine laços para percorrer duas dimensões, prever a ordem das iterações e calcular o trabalho realizado pelo bloco interno.

Conteúdo 33 de 39

Mecanismos desenhados a lápis mostram um controle externo selecionando três fileiras e um controle interno percorrendo quatro células de cada fileira

O laço interno completa um percurso para cada volta externa

Uma estrutura de repetição aninhada coloca um laço dentro do corpo de outro. O laço externo seleciona um contexto; dentro dele, o laço interno percorre todos os elementos daquele contexto.

Imagine um pequeno cinema com três fileiras e quatro assentos em cada uma:

A1  A2  A3  A4
B1  B2  B3  B4
C1  C2  C3  C4

O laço externo pode controlar a fileira, enquanto o interno controla o assento:

PARA CADA fileira EM ["A", "B", "C"] FAÇA
  PARA assento DE 1 ATÉ 4 FAÇA
    EXIBIR fileira, assento
  FIM PARA
FIM PARA

A fileira A permanece selecionada enquanto o laço interno percorre 1, 2, 3 e 4. Somente depois de o laço interno terminar, o externo avança para B e inicia um novo percurso dos assentos.

O laço externo escolhe uma fileira, inicia o laço interno do primeiro assento e somente avança de fileira depois que todos os assentos terminam
O laço interno nasce, completa seu percurso e reinicia para cada novo valor do laço externo.

Aninhar não cria um novo tipo de laço. É uma composição das estruturas que você já conhece, como o for, com responsabilidades diferentes para cada nível.

Acompanhe os pares na ordem em que são produzidos

Em JavaScript, o exemplo fica assim:

const fileiras = ["A", "B", "C"];

for (const fileira of fileiras) {
  for (let assento = 1; assento <= 4; assento += 1) {
    console.log(`${fileira}${assento}`);
  }
}

A saída é:

A1 A2 A3 A4 B1 B2 B3 B4 C1 C2 C3 C4

O rastreamento por volta externa torna o reinício visível:

Fileira externaValores assumidos por assentoPares produzidos
A1, 2, 3, 4A1, A2, A3, A4
B1, 2, 3, 4B1, B2, B3, B4
C1, 2, 3, 4C1, C2, C3, C4
Grade de três fileiras por quatro assentos numerada de 1 a 12, da esquerda para a direita em cada fileira e depois de cima para baixo
A numeração mostra a ordem temporal: quatro visitas na primeira fileira, quatro na segunda e quatro na terceira.

As variáveis têm ciclos de vida distintos. fileira muda três vezes; assento percorre quatro valores em cada uma dessas vezes. Usar nomes que expressem cada dimensão reduz a chance de atualizar ou consultar o nível errado.

Inverter os laços muda a ordem, não necessariamente a cobertura

Troque as posições:

const fileiras = ["A", "B", "C"];

for (let assento = 1; assento <= 4; assento += 1) {
  for (const fileira of fileiras) {
    console.log(`${fileira}${assento}`);
  }
}

Agora a saída é:

A1 B1 C1 A2 B2 C2 A3 B3 C3 A4 B4 C4

Os mesmos doze pares aparecem, mas agrupados por número de assento em vez de fileira. Portanto, duas perguntas devem ser avaliadas separadamente:

  • cobertura: quais combinações serão visitadas;
  • ordem: qual combinação aparece antes de qual.

Em alguns problemas, somente a cobertura importa. Em outros, a ordem afeta a apresentação, o estado acumulado, o acesso aos dados ou a possibilidade de interromper cedo. Escolha o nível externo conforme o contexto que precisa permanecer fixo durante um percurso interno completo.

Calcule o trabalho contando as voltas internas

No cinema:

  • o laço externo executa 3 vezes;
  • para cada uma, o interno executa 4 vezes;
  • o console.log executa 3 × 4 = 12 vezes.

Essa multiplicação funciona porque os quatro assentos são percorridos para cada uma das três fileiras. Para limites independentes com f fileiras e a assentos, o bloco mais interno executa:

f × a

Não conte apenas quantas instruções for aparecem. Conte quantas vezes o corpo interno executa em cada valor externo.

Isso também impede uma conclusão precipitada: dois laços aninhados não significam automaticamente “o primeiro limite ao quadrado”. Se existem 3 fileiras e 100 assentos, são 300 pares, não 100² nem .

Esta aula usa contagem exata para compreender o fluxo. A comparação formal de crescimento e custo pertence à aula posterior de eficiência.

Limites dependentes formam outros desenhos

O número de voltas internas pode depender do valor externo. Para desenhar uma escada com quatro níveis:

for (let linha = 1; linha <= 4; linha += 1) {
  let desenho = "";

  for (let coluna = 1; coluna <= linha; coluna += 1) {
    desenho += "■";
  }

  console.log(desenho);
}

Resultado:

■
■■
■■■
■■■■

O laço interno não executa quatro vezes em toda linha:

linhaVoltas internas
11
22
33
44
Total1 + 2 + 3 + 4 = 10
Um retângulo com três linhas de quatro pontos totaliza doze execuções, enquanto uma escada com uma, duas, três e quatro posições totaliza dez
Limites fixos produzem um retângulo; um limite interno dependente do externo pode produzir uma soma triangular.

Para prever o total, faça uma linha da tabela para cada valor externo e some as voltas internas. Só transforme essa soma em multiplicação quando a quantidade interna realmente for constante.

Cada nível precisa terminar por conta própria

As condições de parada continuam válidas em cada nível:

  • o laço interno precisa avançar até sua própria saída;
  • depois que ele termina, o laço externo precisa avançar;
  • reiniciar o laço interno não pode apagar indevidamente o estado externo;
  • nenhum caminho com continue pode pular a atualização necessária do nível que ele repete.

Se o laço interno fica infinito na fileira A, o externo nunca alcança B. O problema parece envolver a grade inteira, mas a primeira pergunta de diagnóstico é: qual nível deixou de progredir?

Em laços controlados manualmente, use variáveis diferentes:

fileira <- 0

ENQUANTO fileira < 3 FAÇA
  assento <- 0

  ENQUANTO assento < 4 FAÇA
    EXIBIR fileira, assento
    assento <- assento + 1
  FIM ENQUANTO

  fileira <- fileira + 1
FIM ENQUANTO

assento é reiniciado dentro do corpo externo porque cada fileira precisa começar no primeiro assento. fileira é inicializada antes dos dois laços, pois seu estado deve sobreviver a todos os percursos internos.

break normalmente encerra apenas o laço mais interno

Considere uma busca pelo assento B3:

for (const fileira of ["A", "B", "C"]) {
  for (let assento = 1; assento <= 4; assento += 1) {
    if (`${fileira}${assento}` === "B3") {
      break;
    }

    console.log(`${fileira}${assento}`);
  }
}

Ao encontrar B3, break encerra o laço dos assentos. O laço das fileiras continua e começa C1. Em JavaScript e em várias linguagens de sintaxe semelhante, uma interrupção sem rótulo afeta o laço mais próximo.

Quando a intenção é encerrar toda uma busca, uma função pode tornar a saída explícita:

function localizarAssento(alvo) {
  for (const fileira of ["A", "B", "C"]) {
    for (let assento = 1; assento <= 4; assento += 1) {
      const codigo = `${fileira}${assento}`;

      if (codigo === alvo) {
        return { fileira, assento };
      }
    }
  }

  return null;
}

console.log(localizarAssento("B3"));

Resultado:

{ fileira: "B", assento: 3 }

JavaScript também oferece break com rótulo. Antes de usá-lo, avalie se extrair a busca para uma função deixa intenção, resultado e testes mais claros. O importante é escolher conscientemente qual nível deve terminar.

Evite níveis que não representam dimensões reais

Aninhamento é apropriado quando o problema contém relações como:

  • cada fileira com seus assentos;
  • cada produto combinado com cada região;
  • cada dia dividido em horários;
  • cada ponto inicial comparado com candidatos.

Ele merece revisão quando:

  • três ou mais níveis exigem lembrar muitas variáveis ao mesmo tempo;
  • o corpo interno mistura validação, cálculo, formatação e saída;
  • a mesma busca interna é refeita sem necessidade;
  • nomes genéricos como i, j e k escondem o significado;
  • break, continue e sinalizadores tornam o destino do fluxo difícil de prever.

Não remova um laço necessário apenas para reduzir indentação. Primeiro identifique o que cada nível representa; depois considere separar responsabilidades em operações nomeadas. Essa preparação abre o próximo módulo da trilha.

Teste ordem, limites e interrupções

Use um teste de mesa que registre uma linha por execução do corpo mais interno:

PassoValor externoValor internoAçãoHouve interrupção?

Inclua casos com:

  • conjunto externo vazio;
  • conjunto interno vazio;
  • uma única combinação;
  • dimensões diferentes, como 2 × 5;
  • limite interno dependente do externo;
  • alvo encontrado na primeira e na última combinação;
  • alvo ausente;
  • break e continue em cada nível relevante.

Confirme três resultados: pares produzidos, ordem desses pares e quantidade de execuções do corpo interno.

Pratique com rotas e horários

Uma transportadora atende três rotas, Norte, Centro e Sul, em quatro horários: 8, 10, 14 e 16 horas.

  1. gere todos os pares rota–horário, agrupados por rota;
  2. escreva a sequência exata dos doze pares;
  3. inverta os laços e descreva o que muda;
  4. conte as execuções sem executar o código;
  5. altere a regra para que a primeira rota tenha dois horários, a segunda três e a terceira quatro;
  6. interrompa toda a busca ao encontrar Centro–14 usando uma função;
  7. teste rota vazia, horários vazios e alvo ausente.

Explique em uma frase a responsabilidade de cada laço e registre onde a variável interna reinicia.

O que você deve guardar

O laço externo mantém um contexto enquanto o interno completa seu percurso. Por isso, a ordem dos níveis determina a ordem dos pares, e cada variável deve representar claramente a dimensão que controla.

Multiplique as quantidades somente quando o limite interno for constante para cada volta externa; caso contrário, conte e some cada percurso. Verifique término e interrupções nível por nível, lembrando que break sem rótulo normalmente encerra apenas o laço mais próximo. No próximo módulo, entenda por que dividir um algoritmo em partes para reduzir o contexto necessário em cada etapa e concentrar responsabilidades.

Referências