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)
Method 1: Using sorted() and range() (Recommended)
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
FalseHow it works:
sorted(a)arranges the list in ascending order.range(min(a), max(a) + 1)generates the expected consecutive sequence from the smallest to the largest value.- 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
FalseHow it works:
len(set(a)) == len(a)ensures there are no duplicates.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
FalseHow it works:
- The list is sorted to ensure proper order.
- A generator expression checks that
a[i] - a[i-1] == 1for every adjacent pair. all()returnsTrueonly 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])) # FalseOutput:
True
FalseThis 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
TrueCommon 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.4217sSummary
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.