pythonalgorithmmathrangerectangles

How to divide a set of overlapping ranges into non-overlapping ranges?


Let's say you have a set of ranges:

Obviously, these ranges overlap at certain points. How would you dissect these ranges to produce a list of non-overlapping ranges, while retaining information associated with their original range (in this case, the letter after the range)?

For example, the results of the above after running the algorithm would be:


Solution

  • I had the same question when writing a program to mix (partly overlapping) audio samples.

    What I did was add an "start event" and "stop event" (for each item) to a list, sort the list by time point, and then process it in order. You could do the same, except using an integer point instead of a time, and instead of mixing sounds you'd be adding symbols to the set corresponding to a range. Whether you'd generate empty ranges or just omit them would be optional.

    Edit Perhaps some code...

    # input = list of (start, stop, symbol) tuples
    points = [] # list of (offset, plus/minus, symbol) tuples
    for start,stop,symbol in input:
        points.append((start,'+',symbol))
        points.append((stop,'-',symbol))
    points.sort()
    
    ranges = [] # output list of (start, stop, symbol_set) tuples
    current_set = set()
    last_start = None
    for offset,pm,symbol in points:
        if pm == '+':
             if last_start is not None:
                 #TODO avoid outputting empty or trivial ranges
                 ranges.append((last_start,offset-1,current_set))
             current_set.add(symbol)
             last_start = offset
        elif pm == '-':
             # Getting a minus without a last_start is unpossible here, so not handled
             ranges.append((last_start,offset-1,current_set))
             current_set.remove(symbol)
             last_start = offset
    
    # Finish off
    if last_start is not None:
        ranges.append((last_start,offset-1,current_set))
    

    Totally untested, obviously.