bisect

Updated March 13, 2026 · Modules
standard-library algorithms binary-search sorted-lists bisect

The bisect module provides functions for binary search and sorted insertion in lists. These tools let you find insertion points and maintain sorted order without manually searching through your data — essential for any scenario where you need to keep a list sorted while adding elements.

Installation

The bisect module is built into Python’s standard library. No installation is required:

import bisect

bisect_left()

The bisect_left() function finds the leftmost insertion point for a value in a sorted list. If the value already exists in the list, it returns the position of the first occurrence.

import bisect

numbers = [1, 3, 5, 7, 9]

# Find where 4 would fit (between 3 and 5)
pos = bisect.bisect_left(numbers, 4)
print(f"Insert 4 at position: {pos}")  
# Insert 4 at position: 2

# With duplicates - returns first position
data = [1, 2, 2, 2, 3]
left_pos = bisect.bisect_left(data, 2)
print(f"bisect_left: {left_pos}")
# bisect_left: 1

Syntax

bisect.bisect_left(a, x, lo=0, hi=len(a))

Parameters

ParameterTypeDefaultDescription
asequenceSorted list to search
xanyValue to find insertion point for
loint0Lower bound index
hiintlen(a)Upper bound index

bisect_right()

The bisect_right() function finds the rightmost insertion point. If the value already exists, it returns the position after all existing occurrences.

import bisect

numbers = [1, 3, 5, 7, 9]

# Find where 5 would fit (at the rightmost position)
pos = bisect.bisect_right(numbers, 5)
print(f"Insert 5 at position: {pos}")
# Insert 5 at position: 3

# With duplicates - returns position after all 2s
data = [1, 2, 2, 2, 3]
right_pos = bisect.bisect_right(data, 2)
print(f"bisect_right: {right_pos}")
# bisect_right: 4

The module also provides insort_left() and insort_right(), which combine finding the insertion point and inserting the value in one step:

import bisect

sorted_numbers = [1, 3, 5, 7, 9]

# Insert 4 using insort_right (insort_left works similarly)
bisect.insort_right(sorted_numbers, 4)
print(sorted_numbers)
# [1, 3, 4, 5, 7, 9]

# Insert 5 again - goes after existing 5
bisect.insort_right(sorted_numbers, 5)
print(sorted_numbers)
# [1, 3, 4, 5, 5, 7, 9]

Common Patterns

Maintaining a sorted collection

import bisect

class SortedList:
    def __init__(self):
        self._data = []
    
    def add(self, item):
        pos = bisect.bisect_left(self._data, item)
        self._data.insert(pos, item)
    
    def __contains__(self, item):
        pos = bisect.bisect_left(self._data, item)
        return pos < len(self._data) and self._data[pos] == item

sl = SortedList()
sl.add(5)
sl.add(2)
sl.add(8)
print(sl._data)  # [2, 5, 8]

Lookup in sorted data (threshold mapping)

import bisect

thresholds = [0, 18, 35, 50, 65, 100]
labels = ["child", "young adult", "adult", "middle-aged", "senior", "elderly"]

def get_category(age):
    pos = bisect.bisect_right(thresholds, age) - 1
    return labels[max(0, pos)]

print(get_category(10))   # child
print(get_category(25))   # young adult
print(get_category(55))   # middle-aged

Performance

Binary search via bisect functions runs in O(log n) time, compared to O(n) for linear search. For a list of 1 million elements, binary search takes about 20 comparisons — dramatically faster for large datasets.

See Also

  • collections — Specialized container datatypes for queues, counters, and default values
  • itertools — Iterator helpers that pair well with sorted-data workflows
  • list — The built-in sequence type most often used with bisect operations