I have these ranges:
7,10
11,13
11,15
14,20
23,39
I need to perform a union of the overlapping ranges to give ranges that are not overlappi
Here is a one-liner using functools.reduce (assuming (x, 10) and (11, y) overlap):
reduce(
lambda acc, el: acc[:-1:] + [(min(*acc[-1], *el), max(*acc[-1], *el))]
if acc[-1][1] >= el[0] - 1
else acc + [el],
ranges[1::],
ranges[0:1]
)
This begins with the first range and uses reduce to go through the rest of the ranges. It compares the last element (acc[-1]) with the next range (el). If they overlap, it replaces the last element with the min and max of the two ranges (acc[:-1:] + [min, max]). If they don't overlap, it simply puts this new range at the end of the list (acc + [el]).
Example:
from functools import reduce
example_ranges = [(7, 10), (11, 13), (11, 15), (14, 20), (23, 39)]
def combine_overlaps(ranges):
return reduce(
lambda acc, el: acc[:-1:] + [(min(*acc[-1], *el), max(*acc[-1], *el))]
if acc[-1][1] >= el[0] - 1
else acc + [el],
ranges[1::],
ranges[0:1],
)
print(combine_overlaps(example_ranges))
Output:
[(7, 20), (23, 39)]