W3docs

Python enumerate, zip, map e filter

Aprenda como enumerate, zip, map e filter do Python funcionam, com exemplos claros e padrões práticos para um código de iteração mais limpo.

Python oferece quatro funções embutidas — enumerate, zip, map e filter — que substituem padrões comuns de loop com uma única expressão legível. Cada uma retorna um iterador (lazy, com uso eficiente de memória) e se compõem naturalmente com loops for e compreensões de lista.

Este capítulo aborda:

  • enumerate() — loop com índice automático
  • zip() — iterar sobre duas ou mais sequências em paralelo
  • map() — aplicar uma função a cada item
  • filter() — manter apenas os itens que passam em um teste
  • Combinando os quatro em padrões do mundo real
  • Quando preferir uma compreensão de lista

enumerate() — índice durante o loop

Quando você precisa tanto da posição quanto do valor durante um loop, a abordagem ingênua usa um contador manual:

colors = ["red", "green", "blue"]
i = 0
for color in colors:
    print(i, color)
    i += 1

enumerate() faz isso automaticamente. Ele envolve qualquer iterável e produz pares (índice, valor):

colors = ["red", "green", "blue"]
for i, color in enumerate(colors):
    print(i, color)

Saída:

0 red
1 green
2 blue

Começando a partir de um índice diferente

Passe um argumento start para começar a contar a partir de qualquer inteiro:

fruits = ["apple", "banana", "cherry"]
for i, fruit in enumerate(fruits, start=1):
    print(f"{i}. {fruit}")

Saída:

1. apple
2. banana
3. cherry

Isso é útil ao construir listas numeradas para exibição, onde a numeração baseada em 0 parece estranha ao leitor.

enumerate() com uma condição

Como enumerate() é apenas um iterador regular, você pode adicionar testes if dentro do corpo do loop:

scores = [72, 91, 55, 88, 44]
for rank, score in enumerate(scores, start=1):
    if score >= 80:
        print(f"Rank {rank}: score {score} — PASS")

Saída:

Rank 2: score 91 — PASS
Rank 4: score 88 — PASS

Obtendo apenas o índice sem enumerate()

Se você só precisa de um índice e nada mais, range(len(seq)) funciona — mas assim que você também precisar do valor, use enumerate() para evitar escrever seq[i] repetidamente.


zip() — iterar sobre várias sequências em paralelo

zip() combina dois ou mais iteráveis em um único iterador de tuplas, emparelhando itens em posições correspondentes:

names = ["Alice", "Bob", "Charlie"]
scores = [95, 87, 92]

for name, score in zip(names, scores):
    print(f"{name}: {score}")

Saída:

Alice: 95
Bob: 87
Charlie: 92

zip() com três ou mais iteráveis

first = ["a", "b", "c"]
second = [1, 2, 3]
third = [True, False, True]

for x, y, z in zip(first, second, third):
    print(x, y, z)

Saída:

a 1 True
b 2 False
c 3 True

Sequências de comprimentos diferentes

zip() para na sequência mais curta e descarta silenciosamente os itens restantes das sequências mais longas:

short = [1, 2]
long  = [10, 20, 30, 40]

print(list(zip(short, long)))

Saída:

[(1, 10), (2, 20)]

Os valores 30 e 40 de long são descartados. Se você precisar manter todos os itens, use itertools.zip_longest da biblioteca padrão:

from itertools import zip_longest

short = [1, 2]
long  = [10, 20, 30, 40]

print(list(zip_longest(short, long, fillvalue=0)))

Saída:

[(1, 10), (2, 20), (0, 30), (0, 40)]

Convertendo um resultado zipado em lista ou dict

zip() retorna um iterador lazy. Envolva-o em list() para materializar todos os pares de uma vez, ou passe-o para dict() para construir um mapeamento a partir de duas sequências paralelas:

keys   = ["name", "age", "city"]
values = ["Alice", 30, "Paris"]

record = dict(zip(keys, values))
print(record)

Saída:

{'name': 'Alice', 'age': 30, 'city': 'Paris'}

Descompactando com zip(*...)

O truque de desempacotamento com * "reverte" uma sequência de tuplas de volta em sequências separadas:

pairs = [(1, "a"), (2, "b"), (3, "c")]
numbers, letters = zip(*pairs)

print(numbers)  # (1, 2, 3)
print(letters)  # ('a', 'b', 'c')

map() — aplicar uma função a cada item

map(function, iterable) aplica function a cada item e retorna um iterador lazy de resultados. Ele substitui um loop for que constrói uma nova lista transformando cada elemento.

numbers = [1, 2, 3, 4, 5]
squares = map(lambda x: x ** 2, numbers)
print(list(squares))

Saída:

[1, 4, 9, 16, 25]

map() com uma função nomeada

Você pode passar qualquer callable — uma função embutida, uma função definida com def ou uma lambda:

words = ["  hello  ", "  world  ", "  python  "]
stripped = list(map(str.strip, words))
print(stripped)

Saída:

['hello', 'world', 'python']

Aqui str.strip é passado como referência (sem parênteses). map() chama str.strip(word) para cada item.

map() sobre múltiplos iteráveis

Passe iteráveis adicionais para mapear uma função que recebe dois ou mais argumentos. map() então percorre todos os iteráveis em paralelo (como zip(), ele para no mais curto):

a = [1, 2, 3]
b = [10, 20, 30]
totals = list(map(lambda x, y: x + y, a, b))
print(totals)

Saída:

[11, 22, 33]

map() vs compreensão de lista

Ambas as abordagens são válidas. A regra geral:

SituaçãoPrefira
Aplicar uma função nomeada existentemap() — mais curto, sem necessidade de lambda
Escrever uma expressão inlineCompreensão de lista — mais legível
Múltiplas entradas em paralelomap() com múltiplos iteráveis

Formas equivalentes:

# map() with a named function
result = list(map(str.upper, ["a", "b", "c"]))

# list comprehension — same result
result = [s.upper() for s in ["a", "b", "c"]]

filter() — manter apenas os itens que correspondem a uma condição

filter(function, iterable) mantém os itens para os quais function retorna um valor verdadeiro. Retorna um iterador lazy.

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = filter(lambda x: x % 2 == 0, numbers)
print(list(evens))

Saída:

[2, 4, 6, 8, 10]

filter() com uma função nomeada

def is_positive(n):
    return n > 0

values = [-3, -1, 0, 4, 7, -2]
positives = list(filter(is_positive, values))
print(positives)

Saída:

[4, 7]

filter(None, iterable) — remover valores falsy

Passar None como função mantém apenas os itens verdadeiros. Esta é uma maneira rápida de descartar strings vazias, zeros e valores None:

mixed = [0, "hello", "", None, 42, False, "world"]
truthy = list(filter(None, mixed))
print(truthy)

Saída:

['hello', 42, 'world']

filter() vs compreensão de lista

filter() e uma compreensão de lista condicional fazem o mesmo trabalho:

numbers = range(1, 11)

# filter()
evens_f = list(filter(lambda x: x % 2 == 0, numbers))

# list comprehension — equivalent
evens_c = [x for x in numbers if x % 2 == 0]

print(evens_f)  # [2, 4, 6, 8, 10]
print(evens_c)  # [2, 4, 6, 8, 10]

Prefira uma compreensão de lista quando a condição é escrita inline; prefira filter() quando você já tem uma função predicado bem nomeada.


Combinando enumerate, zip, map e filter

Essas quatro funções se compõem naturalmente. Aqui está um exemplo realista: você tem duas listas paralelas de nomes de alunos e notas brutas; quer imprimir um relatório numerado que inclui apenas os alunos aprovados (nota >= 60), com as notas convertidas em conceitos por letras.

def letter_grade(score):
    if score >= 90:
        return "A"
    elif score >= 80:
        return "B"
    elif score >= 70:
        return "C"
    elif score >= 60:
        return "D"
    return "F"

names  = ["Alice", "Bob", "Carol", "Dave", "Eve"]
scores = [85, 52, 91, 67, 48]

# Step 1: pair names with scores
pairs = zip(names, scores)

# Step 2: keep only passing students
passing = filter(lambda pair: pair[1] >= 60, pairs)

# Step 3: convert scores to letter grades
graded = map(lambda pair: (pair[0], letter_grade(pair[1])), passing)

# Step 4: number the results
for rank, (name, grade) in enumerate(graded, start=1):
    print(f"{rank}. {name}: {grade}")

Saída:

1. Alice: B
2. Carol: A
3. Dave: D

Cada etapa produz um iterador; nada é materializado em uma lista até que o loop for o consuma. Isso mantém o uso de memória constante independentemente do tamanho da entrada.


Armadilhas comuns

Iteradores são esgotados após uma única passagem

map(), filter() e zip() retornam iteradores, não listas. Uma vez que você consome um iterador, ele fica vazio:

squares = map(lambda x: x ** 2, [1, 2, 3])
print(list(squares))  # [1, 4, 9]
print(list(squares))  # [] — already exhausted

Envolva em list() antecipadamente se precisar iterar mais de uma vez.

zip() descarta itens finais silenciosamente

Quando as sequências de entrada têm comprimentos diferentes, zip() descarta os elementos extras sem aviso. Sempre verifique os comprimentos explicitamente se isso for importante, ou use itertools.zip_longest.

enumerate() não altera o iterável

enumerate() envolve o iterável original; não o copia. Modificar a lista subjacente durante a iteração pode produzir resultados inesperados — o mesmo cuidado que se aplica a loops for comuns.


Referência rápida

FunçãoAssinaturaO que retorna
enumerateenumerate(iterable, start=0)Iterador de tuplas (index, value)
zipzip(*iterables)Iterador de tuplas, um item de cada iterável por tupla
mapmap(function, *iterables)Iterador de function aplicada a cada item
filterfilter(function, iterable)Iterador de itens onde function retorna True

Todas as quatro são lazy: produzem valores sob demanda em vez de construir uma lista completa antecipadamente.


Prática

Prática
What does enumerate(items, start=1) do when used in a for loop?
What does enumerate(items, start=1) do when used in a for loop?
Prática
What happens when you pass sequences of different lengths to zip()?
What happens when you pass sequences of different lengths to zip()?
Prática
Which statement about map() is correct?
Which statement about map() is correct?
Prática
What does filter(None, iterable) do?
What does filter(None, iterable) do?
Was this page helpful?