Using Python To Merge Array of Ranges
Source: Dev.to
Counting Unique Numbers Across Overlapping Ranges
Inspired by an Advent of Code 2025 challenge and a previous booking‑system implementation.
The Naïve Approach
unique_values = set()
for start, end in ranges:
unique_values.update(range(start, end + 1))
For a range like 1‑100_000_000_000 this would create 1 billion integers in memory – far too expensive. We need a way to count the numbers without materialising every single value.
Solution – Merge First, Count Later
Instead of storing every number, we merge overlapping (or adjacent) ranges into a smaller set of disjoint intervals and then compute the total count mathematically.
Example Ranges
3‑5,
10‑14,
16‑20,
12‑18
10‑14 and 12‑18 overlap (they share 12, 13, 14). Merging them yields 10‑18. Without merging we would double‑count the overlapping part or waste memory.
How to Merge Overlapping Ranges
1️⃣ Sort the Ranges
Sorting by the start position lets us process the intervals from left‑to‑right on the number line.
sorted_ranges = sorted(fresh_ranges)
# Before: [(3,5), (10,14), (16,20), (12,18)]
# After : [(3,5), (10,14), (12,18), (16,20)]
When the list is sorted, any new range can only overlap with the last merged range, so we never need to look back further.
Sorted number line view:
3---5 10----14
12------18
16----20
# Overlaps flow left‑to‑right!
2️⃣ Merge Overlapping / Adjacent Ranges
merged = []
for start, end in sorted_ranges:
# If the current range touches or overlaps the last merged range …
if merged and start <= merged[-1][1] + 1:
# … extend the last merged interval
merged[-1] = (merged[-1][0], max(merged[-1][1], end))
else:
# No overlap – start a new interval
merged.append((start, end))
Why start <= merged[-1][1] + 1?
| Situation | Last merged | Current | Check (start <= last_end + 1) | Result |
|---|---|---|---|---|
| Adjacent (touching) | (10, 14) | (15, 20) | 15 ≤ 14 + 1 → True | Merge |
| Gap | (3, 5) | (10, 14) | 10 ≤ 5 + 1 → False | Separate |
The + 1 allows adjacent intervals (e.g., (5, 9) and (10, 15)) to be merged, because there is no integer between 9 and 10.
Visual illustration
Range A: (5, 9) → 5,6,7,8,9
Range B: (10,15) → 10,11,12,13,14,15
# They touch at 9→10
Check: 10 <= 9 + 1 → True → merge → (5,15)
Range A: (5, 9) → 5,6,7,8,9
Range B: (11,15) → 11,12,13,14,15
# Gap at 10
Check: 11 <= 9 + 1 → False → keep separate
3️⃣ Count the Numbers
After merging, the total number of distinct integers is simply the sum of the lengths of the disjoint intervals.
total_count = sum(end - start + 1 for start, end in merged)
return total_count
Final Implementation
def count_unique_numbers(fresh_ranges):
# 1️⃣ Sort by start position
sorted_ranges = sorted(fresh_ranges)
# 2️⃣ Merge overlapping / adjacent ranges
merged = []
for start, end in sorted_ranges:
if merged and start <= merged[-1][1] + 1:
# Overlap or adjacency – extend the last interval
merged[-1] = (merged[-1][0], max(merged[-1][1], end))
else:
# No overlap – start a new interval
merged.append((start, end))
# 3️⃣ Compute total count
total_count = sum(end - start + 1 for start, end in merged)
return total_count
Real‑Life Use Cases
Appointment Booking Systems
Meeting A: 09:00‑10:30
Meeting B: 10:15‑11:00
Meeting C: 14:00‑15:30
Meeting D: 15:30‑17:00
Sorted: [(09:00,10:30), (10:15,11:00), (14:00,15:30), (15:30,17:00)]
Merged: [(09:00,11:00), (14:00,17:00)]
The merged intervals give the total occupied time without double‑counting overlapping meetings.
Other Scenarios
- IP address allocation – merging CIDR blocks.
- Genome interval analysis – combining overlapping gene regions.
- Log file processing – consolidating time windows of activity.
- Resource reservation – aggregating booked slots for equipment or rooms.
Overlap — Meetings C + D Touch (Adjacent)
Free times:
- Before 9:00
- 11:00 – 14:00
- After 17:00
When is the room actually free?
IP Address Blocking
Block: 192.168.1.0 - 192.168.1.50
Block: 192.168.1.45 - 192.168.1.100
Block: 192.168.1.200 - 192.168.1.255
Without merging: check 3 rules for every connection.
With merging:
[(192.168.1.0, 192.168.1.100), (192.168.1.200, 192.168.1.255)]
Only 2 rules to check → faster firewall!
Maintenance Downtime
Server or machine scheduled for maintenance:
Maintenance A: Hour 0‑5
Maintenance B: Hour 4‑8
Maintenance C: Hour 20‑24
Merged downtime:
[(0, 8), (20, 24)]
Total downtime: 8 + 4 = 12 hours (not 17 hours if counted individually).
Why This Matters in All Cases
- Avoid double‑counting overlapping periods.
- Optimise checks – fewer ranges to search.
- Find gaps – available time slots.
- Accurate reporting – real busy vs. free time.
- Performance – checking fewer merged ranges vs. many overlapping ones.
Conclusion
The above pattern/method is used by multiple companies worldwide for handling calendar invites, database indexing, network‑traffic analysis, and more.
Go ahead—use the code to boost your application’s performance.
If you’d like to chat or reach out, feel free to comment below or drop me a follow on X/Twitter.