bisect no Python: buscas em listas ordenadas

Publicado em: 08/08/2026
Tempo de leitura: 5 minutos
Busca binária e listas ordenadas com bisect no Python

O módulo bisect da biblioteca padrão resolve um problema comum: localizar rapidamente a posição correta de um valor em uma lista já ordenada. Em vez de percorrer todos os elementos, ele aplica busca binária e reduz o número de comparações. Isso é útil em rankings, faixas de preço, tabelas de pontuação, agendas, filas priorizadas e sistemas que mantêm dados em ordem sem depender de bibliotecas externas.

Neste guia, você aprenderá como usar bisect_left, bisect_right, insort_left e insort_right, quando cada função faz sentido, quais são os custos reais e como evitar erros de modelagem.

Por que usar busca binária

Em uma lista comum, procurar um item pode exigir verificar muitos elementos. Em uma lista ordenada, a busca binária compara o valor com o centro da sequência e descarta metade do espaço a cada passo. O custo de localizar a posição é logarítmico, embora inserir em uma lista continue sendo linear porque os elementos seguintes precisam ser deslocados.

Isso significa que bisect é excelente quando há muitas consultas e poucas inserções. Em cargas com inserções intensas, uma árvore balanceada, um banco de dados ou outra estrutura pode ser mais adequada.

bisect_left e bisect_right

from bisect import bisect_left, bisect_right

valores = [10, 20, 20, 20, 30, 40]

inicio = bisect_left(valores, 20)
fim = bisect_right(valores, 20)

print(inicio)  # 1
print(fim)     # 4
print(valores[inicio:fim])  # [20, 20, 20]

bisect_left retorna a primeira posição válida para o item. bisect_right retorna a posição logo após os valores iguais. Essa diferença permite contar duplicatas, criar intervalos e escolher se um novo item deve ficar antes ou depois dos equivalentes.

Inserindo sem perder a ordem

from bisect import insort_left, insort_right

notas = [5.0, 6.5, 8.0, 9.5]
insort_left(notas, 8.0)
insort_right(notas, 8.0)
print(notas)

As funções insort localizam a posição e executam a inserção. O código fica mais claro do que uma busca manual seguida de list.insert. Ainda assim, o deslocamento dos elementos torna a operação linear.

Buscando valores exatos

from bisect import bisect_left

def encontrar_exato(lista, alvo):
    pos = bisect_left(lista, alvo)
    if pos != len(lista) and lista[pos] == alvo:
        return pos
    return -1

É importante verificar o índice retornado. bisect_left informa onde o valor deveria estar, mas isso não garante que ele exista. Sem a validação, o código pode aceitar um item diferente ou acessar uma posição fora da lista.

Criando faixas

from bisect import bisect_right

limites = [18, 30, 45, 60]
rotulos = ["iniciante", "júnior", "pleno", "sênior", "especialista"]

def classificar(idade):
    return rotulos[bisect_right(limites, idade)]

Esse padrão transforma limites ordenados em classificações rápidas. Ele pode ser usado em cálculo de frete, tributação, níveis de serviço, faixas de latência, classificação de notas e regras de desconto.

Usando key em versões modernas do Python

As funções de busca aceitam o parâmetro key para extrair a chave dos elementos. A chave não é aplicada ao valor procurado; por isso, passe ao argumento x uma chave compatível.

from bisect import bisect_left

produtos = [
    {"nome": "A", "preco": 10},
    {"nome": "B", "preco": 25},
    {"nome": "C", "preco": 40},
]

pos = bisect_left(produtos, 30, key=lambda item: item["preco"])
print(pos)  # 2

Em buscas repetidas, a função de chave pode ser chamada muitas vezes. Para chaves caras, considere manter uma lista paralela já calculada ou aplicar cache.

Lista paralela de chaves

from bisect import bisect_left

registros = [
    {"id": 101, "nome": "Ana"},
    {"id": 205, "nome": "Bruno"},
    {"id": 330, "nome": "Carla"},
]
ids = [item["id"] for item in registros]

pos = bisect_left(ids, 205)
if pos < len(ids) and ids[pos] == 205:
    print(registros[pos])

Esse desenho evita recalcular a chave. O cuidado é manter as duas listas sincronizadas em toda inserção, remoção ou atualização.

Erros comuns

O primeiro erro é usar bisect em uma lista não ordenada. A função não valida a ordenação e pode retornar posições aparentemente plausíveis, porém incorretas. O segundo é esquecer que inserir no meio da lista custa tempo linear. O terceiro é confundir a posição de inserção com a confirmação de existência. O quarto é misturar critérios: se a lista foi ordenada por preço, a busca também deve usar preço.

Outro problema aparece em concorrência. Operações compostas de busca e inserção não devem ser tratadas como atômicas quando várias threads ou processos alteram a mesma coleção. Proteja a estrutura com sincronização adequada ou use um armazenamento transacional.

Quando usar e quando evitar

Use bisect em tabelas pequenas ou médias mantidas em memória, configurações estáticas, intervalos ordenados, catálogos com muitas leituras e poucas alterações. Evite-o como substituto de índice de banco de dados em grandes volumes mutáveis, em filas de prioridade com muitas remoções ou em estruturas compartilhadas sem controle de concorrência.

Exemplo completo: ranking ordenado

from bisect import bisect_right

ranking = []
pontos = []

def adicionar(nome, pontuacao):
    pos = bisect_right(pontos, pontuacao)
    pontos.insert(pos, pontuacao)
    ranking.insert(pos, {"nome": nome, "pontos": pontuacao})

def acima_de(minimo):
    pos = bisect_left(pontos, minimo)
    return ranking[pos:]

O exemplo mantém duas listas sincronizadas e permite localizar rapidamente o início de uma faixa. Em aplicações reais, encapsule essas listas em uma classe e teste todas as operações para impedir divergências.

Boas práticas

Documente o critério de ordenação, valide entradas, escreva testes com duplicatas e limites vazios, meça o custo de inserções e encapsule a estrutura. Para aprender mais sobre coleções e organização de dados, consulte os guias sobre difflib, fractions, statistics, types e linecache.

As referências oficiais são a documentação do bisect e a documentação de estruturas de dados.

Conclusão

bisect oferece uma solução pequena, eficiente e previsível para pesquisar posições em listas ordenadas. O ganho principal está nas consultas logarítmicas e na clareza do código. Quando o padrão de acesso combina muitas leituras com poucas inserções, ele costuma ser uma escolha excelente. Quando a coleção cresce ou muda constantemente, use as mesmas medições para decidir se é hora de migrar para uma estrutura especializada.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Documento e caixa de entrada representando caixas de e-mail com mailbox no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    mailbox no Python: caixas de e-mail

    Aprenda mailbox no Python para ler, criar e migrar caixas Maildir, mbox e MH com locking, mensagens, flags e tratamento

    Ler mais

    Tempo de leitura: 6 minutos
    12/08/2026
    Editor de texto representando formatação com textwrap no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    textwrap no Python: formate textos

    Aprenda textwrap no Python para quebrar, preencher, encurtar, indentar e remover recuos de textos com controle de largura e espaços.

    Ler mais

    Tempo de leitura: 5 minutos
    10/08/2026
    Pasta e lupa representando filtros de nomes com fnmatch no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    fnmatch no Python: filtre nomes de arquivos

    Aprenda fnmatch no Python para filtrar nomes de arquivos com curingas, controlar maiúsculas, excluir padrões e evitar confundir glob com

    Ler mais

    Tempo de leitura: 5 minutos
    10/08/2026
    Monitor com dados binários representando arrays numéricos compactos no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    array no Python: números compactos

    Aprenda array no Python para armazenar números compactos, manipular bytes, arquivos binários e buffers com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    10/08/2026
    Círculo cromático representando conversões RGB, HSV e HLS com colorsys no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    colorsys no Python: RGB, HSV e HLS

    Aprenda colorsys no Python para converter cores entre RGB, HSV, HLS e YIQ, gerar paletas e evitar erros com escalas

    Ler mais

    Tempo de leitura: 6 minutos
    09/08/2026
    Ícone de configuração representando arquivos plist com plistlib no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    plistlib: leia e grave arquivos plist

    Aprenda plistlib no Python para ler e gravar arquivos plist XML e binários, validar dados e integrar configurações Apple com

    Ler mais

    Tempo de leitura: 7 minutos
    08/08/2026