Step 0: Make a Range
class for convenience:
from collections import namedtuple
Range = namedtuple("Range", ["start", "end"])
Step 1: Make a function that calculates the intersection between two ranges. This function will work for anything that consists of two comparable points:
def intersect(range1, range2):
new_range = Range(
max(range1.start, range2.start),
min(range1.end, range2.end)
)
return new_range if new_range.start < new_range.end else None
Step 2: Make a function that finds all intersections of two sets of ranges, by just trying all possible combinations.
def intersect_two(ranges1, ranges2):
for range1 in ranges1:
for range2 in ranges2:
intersection = intersect(range1, range2)
if intersection:
yield intersection
Step 3: reduce()
a list of sets of ranges using intersect_two
:
def intersect_all(ranges):
return reduce(intersect_two, ranges)
I'm using integers for simplicity, but it should work just as good with datetime
objects:
>>> timelines = [
... (Range(0, 11), Range(15, 20)),
... (Range(8, 16), Range(19, 25)),
... (Range(0, 10), Range(15, 22)),
... ]
>>>
>>> for intersection in intersect_all(timelines):
... print(intersection)
...
Range(start=8, end=10)
Range(start=15, end=16)
Range(start=19, end=20)