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

前端 未结 5 1137
伪装坚强ぢ
伪装坚强ぢ 2021-02-13 23:22

Let\'s say you have a set of ranges:

  • 0 - 100: \'a\'
  • 0 - 75: \'b\'
  • 95 - 150: \'c\'
  • 120 - 130: \'d\'

Obviously, these range

5条回答
  •  臣服心动
    2021-02-13 23:40

    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.

提交回复
热议问题