Skip to content

How to Check if a List Contains Consecutive Numbers in Python

Learn how to verify if a Python list contains consecutive numbers (like [3, 4, 5]) using efficient methods, including handling duplicates, edge cases, and performance comparisons.

Checking whether a list contains consecutive numbers, i.e. an unbroken sequence like [3, 4, 5, 6], is a common task in data validation, pattern recognition, and algorithm design. For example, you might need to verify that a series of IDs has no gaps, detect sequential runs in game logic, or validate sorted input data.

In this guide, you will learn multiple methods to check for consecutive numbers in a Python list, from concise one-liners to explicit loop-based approaches, along with edge case handling and performance considerations.

What Does "Consecutive" Mean?

A list contains consecutive numbers if, when sorted, each element is exactly 1 greater than the previous element. The list does not need to be sorted initially: [5, 3, 4] is consecutive because it can be arranged as [3, 4, 5].

Consecutive examples:

  • [3, 4, 5, 6] → True
  • [5, 3, 4] → True (order doesn't matter)
  • [10, 11, 12, 13] → True

Non-consecutive examples:

  • [1, 2, 4, 5] → False (gap at 3)
  • [1, 2, 2, 3] → False (duplicate)
  • [5] → True (single element is trivially consecutive)

The most readable approach sorts the list and compares it directly to the expected consecutive range:

def are_consecutive(a):
    if not a:
        return True  # Empty list is trivially consecutive
    return sorted(a) == list(range(min(a), max(a) + 1))

print(are_consecutive([3, 4, 5, 6]))   # True
print(are_consecutive([5, 3, 4]))      # True
print(are_consecutive([1, 2, 4, 5]))   # False (gap at 3)
print(are_consecutive([1, 2, 2, 3]))   # False (duplicate)

Output:

True
True
False
False

How it works:

  1. sorted(a) arranges the list in ascending order.
  2. range(min(a), max(a) + 1) generates the expected consecutive sequence from the smallest to the largest value.
  3. If both match, the list is consecutive.

Method 2: Using set() and Range Length

This method avoids sorting by using set properties: checking that there are no duplicates and that the range of values matches the list length.

def are_consecutive(a):
    if not a:
        return True
    return len(set(a)) == len(a) and max(a) - min(a) + 1 == len(a)

print(are_consecutive([7, 8, 9, 10]))     # True
print(are_consecutive([7, 8, 8, 10]))     # False (duplicate 8)
print(are_consecutive([7, 9, 10, 12]))    # False (gaps)

Output:

True
False
False

How it works:

  1. len(set(a)) == len(a) ensures there are no duplicates.
  2. max(a) - min(a) + 1 == len(a) ensures the range of values exactly matches the number of elements, which is only possible if the numbers are consecutive.

Both conditions must be true simultaneously.

Method 3: Using Sorted Differences with all()

This method sorts the list and verifies that the difference between every pair of adjacent elements is exactly 1:

def are_consecutive(a):
    if len(a) <= 1:
        return True
    a_sorted = sorted(a)
    return all(a_sorted[i] - a_sorted[i - 1] == 1 for i in range(1, len(a_sorted)))

print(are_consecutive([10, 11, 12, 13]))   # True
print(are_consecutive([10, 12, 13, 14]))   # False (gap between 10 and 12)

Output:

True
False

How it works:

  1. The list is sorted to ensure proper order.
  2. A generator expression checks that a[i] - a[i-1] == 1 for every adjacent pair.
  3. all() returns True only if every difference equals 1.

This method can short-circuit: it stops checking as soon as it finds a non-consecutive pair, which is efficient when the "break" in consecutiveness occurs early.

Method 4: Using a Loop (Explicit)

For maximum clarity and control, use an explicit for loop:

def are_consecutive(a):
    if len(a) <= 1:
        return True
    a_sorted = sorted(a)
    for i in range(1, len(a_sorted)):
        if a_sorted[i] - a_sorted[i - 1] != 1:
            return False
    return True

print(are_consecutive([1, 2, 3, 4]))  # True
print(are_consecutive([1, 3, 5, 7]))  # False

Output:

True
False

This is functionally identical to Method 3 but uses an explicit loop instead of all() with a generator. It's easier to debug and extend. For example, you can log exactly where the break occurs:

def find_gaps(a):
    """Find where the consecutive sequence breaks."""
    a_sorted = sorted(a)
    gaps = []
    for i in range(1, len(a_sorted)):
        if a_sorted[i] - a_sorted[i - 1] != 1:
            gaps.append((a_sorted[i - 1], a_sorted[i]))
    return gaps

a = [1, 2, 4, 5, 8]
print(f"Gaps found between: {find_gaps(a)}")

Output:

Gaps found between: [(2, 4), (5, 8)]

Handling Edge Cases

Robust implementations should handle these special cases:

def are_consecutive(a):
    if len(a) <= 1:
        return True  # Empty list or single element
    return len(set(a)) == len(a) and max(a) - min(a) + 1 == len(a)

print(are_consecutive([]))              # True  (empty list)
print(are_consecutive([42]))            # True  (single element)
print(are_consecutive([5, 5]))          # False (duplicates)
print(are_consecutive([-2, -1, 0, 1]))  # True  (negative numbers)
print(are_consecutive([0]))             # True  (zero)

Output:

True
True
False
True
True

Common Mistake: Ignoring Duplicates

A frequent error is only checking the range without verifying uniqueness:

Wrong: does not detect duplicates

def are_consecutive_wrong(a):
    return max(a) - min(a) + 1 == len(a)

print(are_consecutive_wrong([1, 2, 2, 4]))  # True: WRONG!

The list [1, 2, 2, 4] has max - min + 1 = 4 which equals len(a) = 4, but it is not consecutive because 3 is missing and 2 is duplicated.

Correct: also check for duplicates

def are_consecutive_correct(a):
    return len(set(a)) == len(a) and max(a) - min(a) + 1 == len(a)

print(are_consecutive_correct([1, 2, 2, 4]))  # False: correct!

Performance Comparison

Method Time Complexity Space Complexity Short-Circuits Detects Duplicates
sorted() + range() O(n log n) O(n) ❌ No ✅ Yes
set() + range check O(n) O(n) ❌ No ✅ Yes
all() with differences O(n log n) O(n) ✅ Yes ✅ Yes (different diffs)
Explicit loop O(n log n) O(n) ✅ Yes ✅ Yes (different diffs)
import timeit

a = list(range(100000))  # 100k consecutive numbers

t1 = timeit.timeit(lambda: sorted(a) == list(range(min(a), max(a) + 1)), number=50)
t2 = timeit.timeit(lambda: len(set(a)) == len(a) and max(a) - min(a) + 1 == len(a), number=50)

print(f"sorted + range: {t1:.4f}s")
print(f"set + range:    {t2:.4f}s")

Output (approximate):

sorted + range: 1.2534s
set + range:    0.4217s

Summary

Python offers several effective ways to check if a list contains consecutive numbers:

Method Best For
sorted() + range() Readability and simplicity (recommended for clarity)
set() + range length Performance-critical applications (O(n), recommended for speed)
all() with differences Early exit when non-consecutive pairs appear early
Explicit loop Debugging, logging gaps, or extending with custom logic

Key reminders:

  • Always check for duplicates: range length alone is not sufficient.
  • Handle edge cases like empty lists and single-element lists.
  • The set() + range method offers the best O(n) performance.
  • Use the explicit loop approach when you need to identify where gaps occur.
Navigation