SkillsTecnológicas
Menu
Conteúdo da trilha

Como percorrer linhas e colunas de uma matriz

Aprenda a visitar cada célula de uma matriz com laços aninhados, percorrer por linhas ou colunas e escolher limites seguros para grades retangulares e irregulares.

Conteúdo 44 de 52

Grade de três linhas e quatro colunas desenhada a lápis é percorrida por um traço azul contínuo em zigue-zague

Percorrer uma matriz é visitar cada coordenada válida

Percorrer uma matriz significa executar uma ação para cada célula que pertence à grade. Como cada célula possui duas coordenadas, o percurso precisa controlar linha e coluna.

Considere as temperaturas de dois dias em três horários:

const temperaturas = [
  [18, 20, 21],
  [17, 19, 23],
];

A matriz tem duas linhas e três colunas. Um percurso completo deve visitar exatamente estas seis coordenadas:

[0][0]  [0][1]  [0][2]
[1][0]  [1][1]  [1][2]

Esse é o contrato mais importante da aula: cada coordenada válida deve ser processada uma vez, e nenhuma coordenada inválida pode ser acessada. A ordem pode mudar conforme a tarefa; a cobertura não pode perder nem repetir células por engano.

Se linha, coluna e acesso ainda parecem abstratos, revise o que são matrizes antes de montar os laços.

O laço externo escolhe uma linha e o interno percorre suas colunas

O percurso mais comum mantém uma linha selecionada enquanto visita todas as colunas dessa linha:

for (let linha = 0; linha < temperaturas.length; linha += 1) {
  for (let coluna = 0; coluna < temperaturas[linha].length; coluna += 1) {
    const valor = temperaturas[linha][coluna];
    console.log(linha, coluna, valor);
  }
}

O laço externo controla linha. Para cada valor de linha, o laço interno começa em coluna = 0, avança até o fim da linha atual e termina. Só então o laço externo seleciona a próxima linha.

Fluxo mostra o laço externo selecionando uma linha, o laço interno visitando todas as colunas válidas e retornando ao externo para escolher a próxima linha
O laço interno completa uma linha antes que o laço externo avance. Ele reinicia na coluna zero para cada nova linha.

Essa aplicação usa a mesma mecânica das estruturas de repetição aninhadas, mas os limites agora vêm da forma concreta dos dados.

Rastreie a ordem antes de confiar no código

Para a matriz 2 × 3, o percurso anterior produz:

Passolinhacolunatemperaturas[linha][coluna]
10018
20120
30221
41017
51119
61223

Observe a mudança de estado entre os passos 3 e 4: a primeira linha terminou, linha avançou para 1 e um novo laço interno iniciou com coluna = 0.

Um teste de mesa pequeno revela três propriedades ao mesmo tempo:

  • quais coordenadas foram cobertas;
  • em qual ordem elas apareceram;
  • se algum índice ultrapassou o limite.

Não valide um percurso apenas pelo resultado agregado. Uma soma pode coincidir mesmo se uma célula for repetida e outra ignorada. Durante o aprendizado, registre as coordenadas visitadas.

Inverter os laços produz um percurso por colunas

Se a tarefa exige agrupar os valores pelo horário, mantenha a coluna fixa e percorra as linhas:

const quantidadeColunas = temperaturas[0]?.length ?? 0;

for (let coluna = 0; coluna < quantidadeColunas; coluna += 1) {
  for (let linha = 0; linha < temperaturas.length; linha += 1) {
    console.log(linha, coluna, temperaturas[linha][coluna]);
  }
}

A ordem passa a ser:

[0][0], [1][0], [0][1], [1][1], [0][2], [1][2]
Duas matrizes dois por três comparam a sequência de visita por linhas e a sequência por colunas, numerando as mesmas seis células em ordens diferentes
Os dois percursos cobrem as seis células. A escolha do laço externo determina como os resultados ficam agrupados.

Percorrer por linhas é natural para exibir cada registro completo ou processar coleções aninhadas. Percorrer por colunas é útil quando a pergunta se refere a uma mesma característica em todas as linhas, como comparar o mesmo horário em vários dias.

Não inverta os laços por aparência. Pergunte qual dimensão precisa permanecer fixa enquanto a outra varia.

Use um limite para cada dimensão

Em uma matriz retangular, as quantidades de linhas e colunas podem ser diferentes. Por isso, este código está errado:

for (let linha = 0; linha < temperaturas.length; linha += 1) {
  for (let coluna = 0; coluna < temperaturas.length; coluna += 1) {
    console.log(temperaturas[linha][coluna]);
  }
}

Ele usa temperaturas.length nas duas condições. Como a matriz tem duas linhas e três colunas, a coluna 2 nunca será visitada.

O percurso seguro por linhas consulta o comprimento da linha atual:

for (let linha = 0; linha < temperaturas.length; linha += 1) {
  for (let coluna = 0; coluna < temperaturas[linha].length; coluna += 1) {
    // processar temperaturas[linha][coluna]
  }
}

Os nomes também funcionam como verificação: linha compara com a quantidade de linhas; coluna compara com a quantidade de colunas da linha selecionada. i e j são válidos, mas nomes sem significado tornam uma troca de limites menos visível.

A forma da estrutura determina como obter os limites

JavaScript e Python representam com frequência uma grade como uma coleção cujos elementos são outras coleções. O percurso interno pode usar a linha atual.

Em Python, enumerate fornece índice e valor juntos:

temperaturas = [
    [18, 20, 21],
    [17, 19, 23],
]

for indice_linha, linha in enumerate(temperaturas):
    for indice_coluna, valor in enumerate(linha):
        print(indice_linha, indice_coluna, valor)

Já um array multidimensional retangular de C# expõe cada dimensão separadamente:

int[,] temperaturas =
{
    { 18, 20, 21 },
    { 17, 19, 23 }
};

for (int linha = 0; linha < temperaturas.GetLength(0); linha++)
{
    for (int coluna = 0; coluna < temperaturas.GetLength(1); coluna++)
    {
        Console.WriteLine($"[{linha},{coluna}] = {temperaturas[linha, coluna]}");
    }
}

GetLength(0) informa o comprimento da primeira dimensão; GetLength(1), o da segunda. Não transporte a sintaxe de uma linguagem para outra sem verificar qual estrutura está sendo usada.

Linhas irregulares exigem o comprimento da linha atual

Uma coleção de coleções pode ser serrilhada:

const leituras = [
  [12, 15, 18],
  [20],
  [21, 24],
];

Usar o comprimento da primeira linha para todas as outras tentaria acessar posições ausentes. O percurso orientado pela linha atual continua válido:

for (let linha = 0; linha < leituras.length; linha += 1) {
  for (let coluna = 0; coluna < leituras[linha].length; coluna += 1) {
    console.log(leituras[linha][coluna]);
  }
}
Comparação entre usar três colunas fixas em todas as linhas e consultar o comprimento da linha atual em uma coleção com linhas de três, uma e duas células
Em uma coleção irregular, cada volta externa define um novo limite interno. A linha atual é a fonte correta desse limite.

Isso não transforma toda coleção serrilhada em uma matriz retangular. Apenas garante que o percurso respeite a forma existente. Se a regra do domínio exige o mesmo número de colunas, valide a forma e rejeite dados irregulares em vez de aceitá-los silenciosamente.

O percurso por colunas é mais delicado em estruturas serrilhadas: uma determinada coluna pode não existir em todas as linhas. Nesse caso, defina explicitamente se a célula ausente deve ser ignorada, preenchida com um valor padrão ou tratada como erro.

Uma matriz vazia não deve exigir a primeira linha

Este acesso falha quando não há linhas:

const quantidadeColunas = matriz[0].length;

No percurso por linhas, nenhuma leitura prematura é necessária:

for (let linha = 0; linha < matriz.length; linha += 1) {
  for (let coluna = 0; coluna < matriz[linha].length; coluna += 1) {
    // executa somente para células existentes
  }
}

Se matriz for [], o laço externo executa zero vezes. Se for [[]], o externo executa uma vez e o interno, zero. Em ambos os casos, nenhuma célula inválida é lida.

Para percorrer por colunas, você precisa de um contrato mais explícito. Em uma matriz retangular representada por arrays aninhados, pode obter as colunas com matriz[0]?.length ?? 0, depois confirmar que todas as linhas têm esse mesmo tamanho.

O corpo interno pode ler ou transformar a célula

Depois que os limites estão corretos, o corpo interno define a tarefa. Para substituir temperaturas negativas por zero:

function normalizarTemperaturas(matriz) {
  for (let linha = 0; linha < matriz.length; linha += 1) {
    for (let coluna = 0; coluna < matriz[linha].length; coluna += 1) {
      if (matriz[linha][coluna] < 0) {
        matriz[linha][coluna] = 0;
      }
    }
  }

  return matriz;
}

A estrutura de percurso não mudou; somente a operação aplicada à célula. Separe mentalmente duas responsabilidades:

  1. navegação: produzir uma coordenada válida;
  2. processamento: ler, validar, exibir ou alterar o valor dessa coordenada.

Essa separação ajuda a localizar falhas. Se uma célula não apareceu, investigue navegação e limites. Se apareceu com resultado incorreto, investigue a regra aplicada no corpo.

Diagnostique os erros pelo rastro das coordenadas

Erros recorrentes incluem:

  • usar a quantidade de linhas como limite das colunas;
  • usar <= no lugar de < e acessar uma posição depois do fim;
  • incrementar linha dentro do laço de coluna;
  • acessar [coluna][linha] quando o contrato define [linha][coluna];
  • não reiniciar a coluna em um percurso escrito manualmente com while;
  • assumir que todas as linhas têm o comprimento da primeira;
  • consultar matriz[0] antes de verificar se existe uma linha;
  • inverter os laços sem revisar de onde vem o limite interno.

Ao diagnosticar, imprima primeiro somente linha e coluna. A sequência esperada para um percurso por linhas em uma matriz 2 × 3 é:

0,0  0,1  0,2  1,0  1,1  1,2

Se o programa não termina, revise as condições de parada de cada nível. O laço interno deve avançar a coluna; o externo, a linha.

Teste formas que revelem limites trocados

Uma matriz quadrada 3 × 3 pode esconder um erro porque linhas e colunas têm a mesma quantidade. Inclua formas assimétricas e mínimas:

  • []: nenhuma linha;
  • [[]]: uma linha sem colunas;
  • [[7]]: uma única célula;
  • [[1, 2, 3, 4]]: uma linha e quatro colunas;
  • [[1], [2], [3]]: três linhas e uma coluna;
  • uma matriz retangular 2 × 3;
  • uma coleção irregular com linhas de comprimentos diferentes.

Para cada caso, verifique quantidade de visitas, primeira coordenada, última coordenada e ausência de acessos inválidos. Em uma matriz retangular L × C, um percurso completo deve realizar L × C visitas.

Pratique com uma grade de disponibilidade

Considere três salas e quatro horários:

disponibilidade = [
  [true,  false, true,  true ],
  [false, false, true,  false],
  [true,  true,  false, true ]
]
  1. percorra a grade por salas e registre todas as coordenadas;
  2. explique qual laço controla sala e qual controla horário;
  3. inverta os laços para agrupar a saída por horário;
  4. confirme que os dois percursos visitam doze células;
  5. substitua cada false por true em uma cópia de teste;
  6. execute os casos [], [[]], 1 × 4 e 3 × 1;
  7. encurte a segunda linha e decida entre validar a forma ou aceitar uma coleção irregular;
  8. produza um teste de mesa com as quatro primeiras e as duas últimas visitas.

O exercício está completo quando você consegue prever a sequência de coordenadas antes de executar o programa.

O que você deve guardar

Percorrer uma matriz exige um controle para cada dimensão. No percurso por linhas, o laço externo seleciona a linha e o interno visita suas colunas; no percurso por colunas, essa ordem é invertida. Os dois podem cobrir as mesmas células, mas produzem sequências diferentes.

Obtenha cada limite da dimensão que ele controla. Em coleções aninhadas, consultar o comprimento da linha atual trata com segurança linhas vazias e irregulares; em matrizes retangulares próprias, use a API de cada dimensão. Teste formas não quadradas, registre coordenadas e separe navegação de processamento para encontrar erros com rapidez. Para aplicar o mesmo raciocínio sequencial a dados textuais, prossiga para strings como sequências de caracteres.

Referências