itertools.groupby: agrupe dados ordenados corretamente

Publicado em: 30/08/2026
Tempo de leitura: 3 minutos
A person reads 'Python for Unix and Linux System Administration' indoors.

itertools.groupby() agrupa elementos consecutivos que produzem a mesma chave. Ele trabalha de forma preguiçosa, consome o iterável apenas conforme necessário e pode processar grandes fluxos sem carregar todos os dados na memória. Porém, seu comportamento é diferente de um GROUP BY de banco de dados: valores iguais que não estejam adjacentes formam grupos separados.

Neste guia, você aprenderá a ordenar dados antes do agrupamento, consumir os subiteradores corretamente, agregar registros em streaming, trabalhar com objetos e evitar os erros mais comuns.

Primeiro exemplo

from itertools import groupby

valores = [1, 1, 2, 2, 2, 3]
for chave, grupo in groupby(valores):
    print(chave, list(grupo))

O resultado contém um grupo para cada sequência consecutiva de valores iguais.

A regra da adjacência

valores = [1, 2, 1]
print([(k, list(g)) for k, g in groupby(valores)])

O valor 1 aparece em dois grupos, porque os elementos iguais não estão juntos. Para reunir todas as ocorrências por chave, ordene primeiro quando isso fizer sentido.

Ordenar pela mesma chave

registros = [
    {"categoria": "b", "valor": 4},
    {"categoria": "a", "valor": 2},
    {"categoria": "b", "valor": 7},
]

registros.sort(key=lambda item: item["categoria"])
for categoria, grupo in groupby(registros, key=lambda item: item["categoria"]):
    itens = list(grupo)
    print(categoria, itens)

A função usada na ordenação deve ser compatível com a função de chave do agrupamento. Caso contrário, uma mesma chave pode reaparecer em grupos separados.

Os grupos compartilham o iterador

Cada grupo é um subiterador ligado ao iterador principal. Quando o loop avança para a próxima chave, o grupo anterior deixa de estar disponível. Materialize-o imediatamente quando precisar conservar seus itens.

for chave, grupo in groupby(dados, key=obter_chave):
    itens = list(grupo)
    processar(chave, itens)

Agregação sem materializar tudo

for categoria, grupo in groupby(registros, key=lambda r: r.categoria):
    total = sum(item.valor for item in grupo)
    print(categoria, total)

Nesse caso, o grupo é consumido diretamente por sum. Isso reduz memória e combina bem com arquivos ordenados, logs e resultados de consultas.

Contagem por grupo

for chave, grupo in groupby(dados, key=obter_chave):
    quantidade = sum(1 for _ in grupo)
    print(chave, quantidade)

O padrão evita criar uma lista apenas para usar len.

Agrupando objetos

from operator import attrgetter

pedidos.sort(key=attrgetter("cliente_id"))
for cliente_id, grupo in groupby(pedidos, key=attrgetter("cliente_id")):
    processar_pedidos(cliente_id, grupo)

operator.attrgetter pode deixar a intenção mais clara que uma lambda repetida.

Dados já ordenados

Quando uma consulta SQL usa ORDER BY, um arquivo é produzido em ordem ou um pipeline garante monotonicidade, groupby pode agregar em streaming. Esse é um dos seus melhores casos de uso.

Diferença para um dicionário

Um dicionário de listas agrupa independentemente da ordem, mas precisa manter todas as coleções em memória. groupby preserva o fluxo e usa pouca memória, desde que os dados estejam adjacentes por chave.

Diferença para pandas

pandas.DataFrame.groupby oferece operações vetorizadas, índices e agregações tabulares. itertools.groupby é mais leve e apropriado para iteradores Python, streams e transformações da biblioteca padrão.

Normalização da chave

nomes.sort(key=lambda nome: nome.casefold())
for chave, grupo in groupby(nomes, key=lambda nome: nome.casefold()):
    print(chave, list(grupo))

Use a mesma normalização para ordenar e agrupar. Para texto humano, considere locale e regras de Unicode.

Grupos aninhados

dados.sort(key=lambda r: (r.pais, r.cidade))
for pais, grupo_pais in groupby(dados, key=lambda r: r.pais):
    itens_pais = list(grupo_pais)
    for cidade, grupo_cidade in groupby(itens_pais, key=lambda r: r.cidade):
        processar(pais, cidade, grupo_cidade)

Materializar o grupo externo pode ser necessário porque o iterador principal é compartilhado.

Erros comuns

  • Esperar que chaves iguais não adjacentes sejam reunidas.
  • Ordenar com uma chave e agrupar com outra.
  • Guardar o subiterador para consumir mais tarde.
  • Converter todos os grupos em listas sem necessidade.
  • Executar a função de chave com efeitos colaterais.

Boas práticas

Documente se a entrada precisa estar ordenada, mantenha a função de chave pura, consuma cada grupo antes de avançar e escolha entre streaming e materialização conscientemente. Veja também os guias internos sobre itertools no Python e itertools.pairwise.

Conclusão

itertools.groupby é uma ferramenta eficiente para segmentar sequências ordenadas e realizar agregações preguiçosas. Entender a adjacência e o compartilhamento do iterador evita resultados incorretos e permite pipelines de baixo consumo de memória.

Fontes externas

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    High-angle view of woman coding on a laptop, with a Python book nearby. Ideal for programming and tech content.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    contextlib.chdir: riscos ao trocar diretórios

    Aprenda contextlib.chdir no Python, seus riscos com estado global e concorrência e quando preferir pathlib ou subprocess cwd.

    Ler mais

    Tempo de leitura: 3 minutos
    30/08/2026
    A person typing on a laptop with a Python programming book visible, capturing technology and learning.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    nullcontext no Python: contextos opcionais

    Use nullcontext no Python para unificar contextos opcionais, recursos já abertos, locks e transações sem duplicar código.

    Ler mais

    Tempo de leitura: 5 minutos
    30/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    contextlib.aclosing: feche geradores async

    Aprenda contextlib.aclosing no Python para fechar geradores assíncronos em break, return, exceções e cancelamentos com segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    30/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    weakref.finalize: limpeza automática sem reter objetos

    Aprenda weakref.finalize no Python para limpar recursos sem manter objetos vivos, usando close, detach, alive e callbacks seguros.

    Ler mais

    Tempo de leitura: 6 minutos
    30/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    SimpleNamespace: objetos leves com atributos

    Aprenda SimpleNamespace no Python para criar objetos leves por atributos, converter dicionários e escolher entre dataclass e TypedDict.

    Ler mais

    Tempo de leitura: 5 minutos
    29/08/2026
    Close-up of a detailed South America map showcasing geography and cartography.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ChainMap no Python: mapas em camadas

    Aprenda ChainMap no Python para combinar configurações e escopos em camadas, controlar precedência, escrita e snapshots.

    Ler mais

    Tempo de leitura: 6 minutos
    29/08/2026