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

    Código e arquivos empacotados com importlib.resources no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    importlib.resources no Python: guia prático

    Aprenda importlib.resources no Python para acessar arquivos empacotados com segurança em pacotes, wheels e aplicações instaladas.

    Ler mais

    Tempo de leitura: 6 minutos
    07/08/2026
    Teclado e fluxo de dados representando leitura de vários arquivos com fileinput no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    fileinput no Python: leia vários arquivos

    Aprenda fileinput no Python para ler vários arquivos ou stdin, rastrear linhas, abrir gzip e reescrever conteúdo com backup e

    Ler mais

    Tempo de leitura: 8 minutos
    07/08/2026
    Editor de código com linhas numeradas representando o módulo linecache no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    linecache no Python: leia linhas por número

    Aprenda linecache no Python para ler linhas por número, usar cache, atualizar arquivos modificados e integrar fontes com traceback e

    Ler mais

    Tempo de leitura: 7 minutos
    07/08/2026
    Dados binários representando serialização interna com marshal no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    marshal no Python: serialização interna

    Aprenda marshal no Python para serializar tipos internos, controlar versões e bloquear objetos de código com segurança.

    Ler mais

    Tempo de leitura: 7 minutos
    06/08/2026
    Monitor com código binário representando personalização de pickle com copyreg no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    copyreg no Python: personalize o pickle

    Aprenda copyreg no Python para registrar funções de redução, personalizar pickle e preservar compatibilidade de objetos.

    Ler mais

    Tempo de leitura: 6 minutos
    06/08/2026
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    functools.partial no Python: guia prático

    Aprenda functools.partial no Python para fixar argumentos, adaptar callbacks e criar funções especializadas com clareza.

    Ler mais

    Tempo de leitura: 6 minutos
    06/08/2026