Pular para o conteúdo
Editor

Laços aninhados em Python: padrões, desempenho e quando evitar

Intermediário25 min6 exercícios80 XP

Este tutorial foi traduzido do original em inglês.Read in EnglishLeer en españolЧитать на русскомอ่านภาษาไทยAvisar sobre um erro de tradução

0/6 exercícios

Pense em uma planilha. Ela tem linhas e colunas. Para ler cada célula, você passa por cada linha e, em cada linha, passa por cada coluna. São dois laços, um dentro do outro. Isso é um laço aninhado.

Os laços aninhados aparecem em todo lugar na programação: para desenhar padrões em grade, procurar em tabelas, gerar combinações e processar imagens pixel por pixel. Eles são poderosos, mas também podem ser surpreendentemente lentos se você não tomar cuidado.

Neste tutorial, você vai aprender como os laços aninhados funcionam, ver exemplos práticos com grades e combinações, entender por que eles podem ser lentos e descobrir quando usar alternativas.

Como funcionam os laços aninhados em Python?

Um laço aninhado é um laço dentro de outro laço. O laço externo começa primeiro. A cada iteração do laço externo, o laço interno roda inteiro, do começo ao fim.

Um laço aninhado básico
for row in range(1, 4): # Outer loop: rows 1, 2, 3
for col in range(1, 4): # Inner loop: columns 1, 2, 3
print(f'({row},{col})', end=' ')
print() # New line after each row
Saída
(1,1) (1,2) (1,3) 
(2,1) (2,2) (2,3) 
(3,1) (3,2) (3,3)

Aqui está a ideia principal: se o laço externo roda n vezes e o laço interno roda m vezes, o código dentro do laço interno é executado n x m vezes no total. Três linhas e três colunas significam que o print() interno roda 9 vezes.

Contando as iterações de um laço aninhado
# Counting total iterations
count = 0
for i in range(5): # 5 iterations
for j in range(3): # 3 iterations each time
count += 1
print(f'Total iterations: {count}') # 5 x 3 = 15
Saída
Total iterations: 15

Trabalhando com dados em 2D (grades e tabelas)

O uso mais prático dos laços aninhados é trabalhar com dados bidimensionais. Uma lista de listas em Python representa uma grade, uma tabela ou uma matriz. O laço externo percorre as linhas, e o laço interno percorre as colunas de cada linha.

Percorrendo uma grade 2D
# A 3x3 grid represented as a list of lists
grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Print every element
for row in grid:
for value in row:
print(value, end=' ')
print() # New line after each row
Saída
1 2 3 
4 5 6 
7 8 9

Às vezes você precisa do índice da linha e da coluna, não só dos valores. Use enumerate() para isso.

Usando enumerate com laços aninhados
grid = [
['X', 'O', 'X'],
['O', 'X', 'O'],
['O', 'O', 'X']
]
# Find all positions where X appears
for r, row in enumerate(grid):
for c, cell in enumerate(row):
if cell == 'X':
print(f'X found at row {r}, col {c}')
Saída
X found at row 0, col 0
X found at row 0, col 2
X found at row 1, col 1
X found at row 2, col 2

Aqui vai um exemplo prático: montar uma tabuada.

Tabuada com laços aninhados
# Multiplication table (1 through 5)
for row in range(1, 6):
for col in range(1, 6):
product = row * col
print(f'{product:4}', end='')
print()
Saída
   1   2   3   4   5
   2   4   6   8  10
   3   6   9  12  15
   4   8  12  16  20
   5  10  15  20  25

Gerando combinações com laços aninhados

Os laços aninhados são perfeitos para gerar todas as combinações de itens de dois (ou mais) grupos. O laço externo escolhe do primeiro grupo, e o laço interno escolhe do segundo.

Todas as combinações de cores e tamanhos
colors = ['red', 'blue']
sizes = ['S', 'M', 'L']
print('All t-shirt options:')
for color in colors:
for size in sizes:
print(f' {color} - {size}')
Saída
All t-shirt options:
  red - S
  red - M
  red - L
  blue - S
  blue - M
  blue - L

Com 2 cores e 3 tamanhos, você obtém 6 combinações. Cada cor é combinada com cada tamanho. Isso se chama produto cartesiano das duas listas.

Encontrando pares com uma soma-alvo
# Finding pairs that add up to a target
numbers = [1, 3, 5, 7, 9]
target = 10
print(f'Pairs that sum to {target}:')
for i in range(len(numbers)):
for j in range(i + 1, len(numbers)): # Start j after i to avoid duplicates
if numbers[i] + numbers[j] == target:
print(f' {numbers[i]} + {numbers[j]} = {target}')
Saída
Pairs that sum to 10:
  1 + 9 = 10
  3 + 7 = 10

Desenhando padrões com laços aninhados

Desenhar padrões é um exercício clássico para entender laços aninhados. Cada linha é controlada pelo laço externo, e o número de caracteres em cada linha é controlado pelo laço interno.

Triângulo retângulo de estrelas
# Right triangle pattern
n = 5
for row in range(1, n + 1):
for col in range(row):
print('*', end='')
print()
Saída
*
**
***
****
*****

O segredo é que o intervalo do laço interno depende da variável do laço externo. Na linha 1, o laço interno roda uma vez. Na linha 2, duas vezes. Na linha 5, cinco vezes. É isso que cria o formato de escada.

Triângulo invertido (um jeito mais simples)
# Inverted triangle
n = 5
for row in range(n, 0, -1):
print('*' * row)
Saída
*****
****
***
**
*

Desempenho: por que os laços aninhados podem ser lentos

Um laço simples sobre 1.000 itens roda 1.000 vezes. Um laço aninhado sobre 1.000 itens roda 1.000 x 1.000 = 1.000.000 de vezes. Isso é um milhão de operações. Acrescente um terceiro nível de aninhamento e você chega a um bilhão. Os laços aninhados se multiplicam, e os números crescem rápido.

Os cientistas da computação descrevem isso com a notação Big O. Um laço simples é O(n): o tempo cresce de forma linear com o tamanho dos dados. Um laço aninhado é O(n²): o tempo cresce com o quadrado do tamanho dos dados. Dobre a entrada e o trabalho quadruplica.

Comparando a velocidade de um laço simples e de um laço aninhado
import time
# O(n) - single loop
n = 2000
start = time.time()
total = 0
for i in range(n):
total += i
single_time = time.time() - start
# O(n²) - nested loop
start = time.time()
total = 0
for i in range(n):
for j in range(n):
total += 1
nested_time = time.time() - start
print(f'Single loop: {single_time:.4f} seconds')
print(f'Nested loop: {nested_time:.4f} seconds')
print(f'Nested is {nested_time / max(single_time, 0.0001):.0f}x slower')
Saída
Single loop: 0.0000 seconds
Nested loop: 0.8120 seconds
Nested is 8120x slower

Quando evitar laços aninhados

Nem todo problema que parece precisar de laços aninhados precisa de fato. Muitas vezes existe um caminho mais rápido usando conjuntos, dicionários ou funções embutidas.

O(n²): laço aninhado para procurar duplicatas
nums = [3, 1, 4, 1, 5, 9]
has_dup = False
for i in range(len(nums)):
    for j in range(i+1, len(nums)):
        if nums[i] == nums[j]:
            has_dup = True
print(has_dup)  # True
O(n): use um conjunto
nums = [3, 1, 4, 1, 5, 9]
has_dup = len(nums) != len(set(nums))
print(has_dup)  # True

A versão com conjunto não é só mais curta: ela é muito mais rápida. Para 10.000 itens, a versão com laço aninhado faz 50 milhões de comparações. A versão com conjunto faz cerca de 10.000 operações. Isso é 5.000 vezes mais rápido.

O(n²): laço aninhado para encontrar um valor
students = [
    {'name': 'Alice', 'id': 101},
    {'name': 'Bob', 'id': 102},
    {'name': 'Charlie', 'id': 103}
]
ids_to_find = [103, 101]

for target_id in ids_to_find:
    for s in students:
        if s['id'] == target_id:
            print(s['name'])
O(n): monte um dicionário primeiro
students = [
    {'name': 'Alice', 'id': 101},
    {'name': 'Bob', 'id': 102},
    {'name': 'Charlie', 'id': 103}
]
ids_to_find = [103, 101]

lookup = {s['id']: s['name'] for s in students}
for target_id in ids_to_find:
    print(lookup[target_id])

Exercícios práticos

Estes exercícios vão reforçar o seu entendimento de laços aninhados. Eles começam com padrões básicos e vão em direção a problemas do mundo real.

Exercício 1: desenhe um retângulo
Escreva o código

Exiba um retângulo de estrelas com 3 linhas e 5 colunas. Cada linha deve ter 5 estrelas, sem espaços entre elas.

Saída esperada:

*****
*****
*****
# Print a 3x5 rectangle of stars
Exercício 2: preveja a saída
Preveja a saída

Sem executar o código, preveja o que ele vai exibir. Conte o número total de linhas da saída. Depois execute para conferir.

for i in range(3):
for j in range(2):
print(f'{i}-{j}')
Exercício 3: triângulo de números
Escreva o código

Exiba um triângulo de números em que cada linha contém o número da linha repetido. O triângulo tem 4 linhas.

Saída esperada:

1
22
333
4444
# Print a number triangle with 4 rows
Exercício 4: some todos os valores da grade
Escreva o código

Uma grade de números já está pronta. Use laços aninhados para calcular e exibir a soma de todos os valores da grade.

Saída esperada:

45
grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Calculate the sum of all values
Exercício 5: todas as combinações de roupa
Escreva o código

Dada uma lista de peças de cima e outra de peças de baixo, exiba todas as combinações de roupa possíveis e, no final, o total.

Saída esperada:

shirt + jeans
shirt + shorts
sweater + jeans
sweater + shorts
hoodie + jeans
hoodie + shorts
Total outfits: 6
tops = ['shirt', 'sweater', 'hoodie']
bottoms = ['jeans', 'shorts']
# Print all combinations and the total count
Exercício 6: corrija a grade de coordenadas
Corrija o erro

Este código deveria exibir uma grade de coordenadas 3x3, mas tem um bug. A saída deve mostrar uma linha de coordenadas por linha de texto, com x indo de 0 a 2 e y indo de 0 a 2.

Saída esperada:

(0,0) (0,1) (0,2)
(1,0) (1,1) (1,2)
(2,0) (2,1) (2,2)

Encontre e corrija o bug.

for x in range(3):
for y in range(3):
print(f'({x},{y})', end=' ')
print()

Resumo: laços aninhados em Python

Veja o que você aprendeu sobre laços aninhados:

ConceitoIdeia principal
Laço aninhadoUm laço dentro de outro laço
Total de iteraçõesVezes do externo x vezes do interno
Dados em 2DLaço externo = linhas, laço interno = colunas
CombinaçõesCombinar cada item do grupo A com cada item do grupo B
DesempenhoO(n²): dobre a entrada e o trabalho quadruplica
AlternativasConjuntos e dicionários muitas vezes substituem laços aninhados

Regras práticas:

  • Pense no tamanho dos dados antes de aninhar laços
  • Use nomes de variáveis que digam algo (row/col, não i/j)
  • A multiplicação de strings ('*' * n) muitas vezes substitui laços internos em padrões
  • Para procurar itens, um dicionário ou um conjunto é quase sempre mais rápido do que um laço aninhado
  • O que vem a seguir?

    No próximo tutorial, Como ler as mensagens de erro do Python, você vai aprender a decifrar as mensagens de erro do Python, corrigir os bugs mais comuns e perder o medo dos tracebacks. Depurar é uma habilidade que facilita todo o resto.

    Tutoriais relacionados

    Este tutorial foi útil?