python
index
sorted-list
search
threshold

In Python, how do you find the index of the first value greater than a threshold in a sorted list?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If a list is already sorted, the right tool for finding the first value greater than a threshold is binary search. In Python, that usually means the bisect module, which gives you the insertion point where the threshold would go while keeping the list sorted.

Use bisect_right for “Greater Than”

For the first value strictly greater than x, use bisect_right. It returns the index immediately after any entries equal to x, which is exactly where values greater than x begin.

python
1from bisect import bisect_right
2
3values = [1, 3, 3, 5, 8, 13]
4threshold = 3
5
6index = bisect_right(values, threshold)
7print(index)
8print(values[index])

The output index is 3, which points to 5, the first value greater than 3.

This runs in O(log n) time because bisect uses binary search.

Handle the “Not Found” Case

If the threshold is greater than or equal to every value in the list, bisect_right returns len(values). That is not an error, but it does mean there is no valid element at that index.

A safe helper function looks like this:

python
1from bisect import bisect_right
2
3
4def first_greater_index(values: list[int], threshold: int) -> int | None:
5    index = bisect_right(values, threshold)
6    return index if index < len(values) else None
7
8
9print(first_greater_index([1, 3, 3, 5, 8, 13], 3))
10print(first_greater_index([1, 3, 3, 5, 8, 13], 20))

Returning None is often clearer than forcing the caller to interpret len(values) manually.

Know the Difference Between bisect_left and bisect_right

This is where many bugs come from:

  • 'bisect_left(values, x) gives the first position where x could be inserted'
  • 'bisect_right(values, x) gives the first position after existing copies of x'

So:

  • first value greater than x uses bisect_right
  • first value greater than or equal to x uses bisect_left

Example:

python
1from bisect import bisect_left, bisect_right
2
3values = [2, 4, 4, 4, 7]
4
5print(bisect_left(values, 4))
6print(bisect_right(values, 4))

The first result is the index of the first 4. The second result is the index of the first value greater than 4.

Why Not Use a Loop

You could scan from left to right:

python
1def first_greater_index_linear(values: list[int], threshold: int) -> int | None:
2    for index, value in enumerate(values):
3        if value > threshold:
4            return index
5    return None

That is fine for small lists, but it is O(n). If the list is already sorted, a linear scan throws away the main advantage of the data structure.

For a one-off search on a tiny list, the difference does not matter. For repeated searches or large arrays, bisect is the correct answer.

Using a Key with Structured Records

If you are working with records instead of plain numbers, the general idea is the same: search on a derived key. In Python 3.10 and newer, bisect functions support a key parameter.

python
1from bisect import bisect_right
2
3rows = [
4    {"score": 10},
5    {"score": 15},
6    {"score": 15},
7    {"score": 22},
8]
9
10index = bisect_right(rows, 15, key=lambda row: row["score"])
11print(index)
12print(rows[index])

If you are on an older Python version, build a separate list of keys and bisect that instead.

Common Pitfalls

The most common mistake is using bisect_left when the requirement says strictly greater than. That returns the first equal value, not the first larger one.

Another issue is forgetting to handle the case where no larger value exists. If the result equals the length of the list, indexing into the list will raise an error.

Developers also sometimes use bisect on data that is not actually sorted. Binary search assumes the order invariant is true. If the list is unsorted, the answer is meaningless.

Finally, be explicit about duplicates. The whole reason bisect_right exists is to move past repeated threshold values cleanly.

Summary

  • Use bisect_right to find the first value strictly greater than a threshold.
  • The result is an index in O(log n) time.
  • If the result equals len(values), no such value exists.
  • Use bisect_left instead when the condition is greater than or equal.
  • Binary search only works when the list is already sorted.

Course illustration
Course illustration

All Rights Reserved.