Python 消除重叠间隔

Python 消除重叠间隔,python,algorithm,intervals,overlap,Python,Algorithm,Intervals,Overlap,我正在尝试编写一些代码来消除重叠(打开)间隔。我从中得到了灵感 间隔表示物理实体。他们的位置是通过某种方式估计的,但这种不完美的估计会导致这些物理实体的位置重叠。然而,实际上这些物理实体不能占据相同的空间,所以我用这个代码来重新调整它们的位置。这种调整应尽可能少地移动这些实体,并尽可能多地保持其估计的相对位置。由于这些是物理实体,因此每个间隔的长度不能更改 代码在大多数情况下运行良好,但在某些情况下会挂起,如下所示: intervals = [(0, 8), (9, 13), (11, 14),

我正在尝试编写一些代码来消除重叠(打开)间隔。我从中得到了灵感

间隔表示物理实体。他们的位置是通过某种方式估计的,但这种不完美的估计会导致这些物理实体的位置重叠。然而,实际上这些物理实体不能占据相同的空间,所以我用这个代码来重新调整它们的位置。这种调整应尽可能少地移动这些实体,并尽可能多地保持其估计的相对位置。由于这些是物理实体,因此每个间隔的长度不能更改

代码在大多数情况下运行良好,但在某些情况下会挂起,如下所示:

intervals = [(0, 8), (9, 13), (11, 14), (15, 21)]
这是我的python代码。有什么建议吗

def intervalLength(interval):
'''
Finds the length of an interval, supplied as a tupple
'''
return interval[1]-interval[0]

def findOverlappingIntervals(intervals):
# https://stackoverflow.com/questions/4542892/possible-interview-question-how-to-find-all-overlapping-intervals?rq=1
# Throw the endpoints of the intervals into an array, marking them as either start- or end-points.
# Sort them by breaking ties by placing end-points before start-points if the intervals are closed, or the other way around if they're half-open.
'''
Takes a list of intervals and returns the intervals that overlap.
List returned has nested list composed of the intervals that overlap with each other
Assumes list is ordered by the start position of the intervals
'''
end_points = []
for n,i in enumerate(intervals):
    end_points.append((i[0],'b',n)) #'b' = beginning of interval
    end_points.append((i[1],'e',n)) #'e' = end of interval
end_points.sort()
b = 0
e = 0
overlapping = [set()]
open_intervals = set()
for ep,sORe,i in end_points:
    if sORe == 'b':
        b += 1
        open_intervals.add(i)
        if b-e > 1 and i in open_intervals:
            overlapping[-1].update(open_intervals)
        elif len(overlapping[-1]) > 0:
            overlapping.append(set())
    else:
        e += 1
        open_intervals.remove(i)

overlapping = [o for o in overlapping if len(o) > 0]
overlapping = [[intervals[i] for i in o] for o in overlapping]

return overlapping

def deOverlap(intervals):
'''
Takes a list of overlapping intervals and returns a new list with updated postions
without overlap and intervals separated by 1, maintaining the previous center
'''
# Find center of overlapping intervals
avg = (reduce(lambda x,y: x+y, [a+b for a,b in intervals])+len(intervals)-1)/(len(intervals)*2.0)

# Find the total length of the ovrlapping intervals
tot_length = reduce(lambda x,y: x+y, [intervalLength(i) for i in intervals]) + len(intervals) - 1

# Find new start position for the overlapping intervals
new_start = int(round(avg-(tot_length/2.0)))

# Place first interval in new position
non_over_intervals = [(new_start, new_start+intervalLength(intervals[0]))]

# Place rest of intervals in new positions
for i in intervals[1:]:
    start = non_over_intervals[-1][1]+1
    non_over_intervals.append((start,start+intervalLength(i)))

return non_over_intervals

def deOverlapIntervals(intervals):
'''
Takes a list of intervals and returns a list with the same intervals with no overlap and
located as close to the original locations as possible
'''
non_over_intervals = intervals
i = 0
while len(findOverlappingIntervals(non_over_intervals)) > 0:
    if i >= 10000:
        print 'Tried 10,000 times and did not finish de-overlapping. Returning best I could do'
        return non_over_intervals
    overlapping_intervals = findOverlappingIntervals(non_over_intervals)
    non_over_intervals = set(non_over_intervals) - set([oi for group in overlapping_intervals for oi in group])
    for oi in overlapping_intervals:
        non_overlapping = deOverlap(oi)
        non_over_intervals.update(non_overlapping)
    non_over_intervals = list(non_over_intervals)
    non_over_intervals.sort()
    i += 1
return non_over_intervals
这些间歇时间很好

intervals = [(-5,-1), (0,6), (7,11), (9,14), (12,17), (21,24), (27,32), (32,36), (39,41)]
这些没有。它们挂起是因为间隔不断移动并与左端或右端重叠

intervals = [(0, 8), (9, 13), (11, 14), (15, 21)]

non_over_intervals = deOverlapIntervals(intervals)

你不能简单一点吗?像这样:

result = intervals[:1]

for begin, end in intervals[1:]:
    if begin <= result[-1][1]:
        result[-1] = (result[-1][0], end)
    else:
        result.append((begin, end))
result=间隔[:1]
对于开始,以间隔[1:]结束:
如果像这样开始

intervals = [(0, 8), (9, 13), (11, 14), (15, 21)]
intervals = [list(t) for t in intervals]

for i in range(len(intervals) - 1):
    offset = intervals[i + 1][0] - intervals[i][1]
    if offset < 1:
        diff = intervals[i + 1][1] - intervals[i + 1][0]
        intervals[i + 1][0] = intervals[i][1] + 1
        intervals[i + 1][1] = intervals[i + 1][0] + diff

print(intervals)
interval=[(0,8)、(9,13)、(11,14)、(15,21)]
间隔=[间隔中t的列表(t)]
对于范围内的i(长度(间隔)-1):
偏移量=间隔[i+1][0]-间隔[i][1]
如果偏移量小于1:
diff=区间[i+1][1]-区间[i+1][0]
区间[i+1][0]=区间[i][1]+1
区间[i+1][1]=区间[i+1][0]+diff
打印(间隔)

我发现,如果移动一个时间间隔会使它与另一个时间间隔重叠,那么将原始重叠的时间间隔和将在单个DeOverlapInterval运行中与该时间间隔重叠的时间间隔都包括在内,就可以解决问题。

对于工作情况是[-6,-2](-1,5)、(6,10)、(11,16)、(17,22)、(23,26)、(27,32), (33, 37), (39, 41)]. 对于非工作情况,它应该是[(0,8)、(9,13)、(14,17)、(18,24)]。我的目标是消除重叠间隔,同时保持结果位置和间隔之间的相对位置尽可能接近原始位置。我不明白“消除重叠”
[(0,8)、(9,13)、(11,14)、(15,21)]
将如何导致
[(0,8)、(9,13)、(14,17)、(18,24)]
。也许你可以编辑这个问题来更清楚地解释这意味着什么。例如,假设输入结束于
21
,那么结果究竟如何结束于
24
?这对我来说没有任何意义。您的工作案例如何包括-6,非工作案例如何包括24?这些似乎超出了提供的范围。因此,如果存在重叠,您的计划是增加以下数字的值。以下间隔的第一个值为
min(项目[n][1]+1,项目[n+1,0])
?这将保留整套重叠间隔的起始位置,但不会保留这些重叠间隔与其他不重叠间隔的相对位置。这就是为什么我要麻烦地编写这个更复杂的代码,它将向左和向右调整以保持重叠间隔的中心(如中所述。我的目标是消除重叠间隔,同时保持结果位置和间隔之间的相对位置尽可能接近原始位置。每个间隔的长度不应更改。我提供的间隔列表是较长间隔集的一部分,因此代码的其余部分有助于识别重叠ng间隔和消除重叠间隔的多个子集。有意义吗?感谢Klaus。这假设一组重叠间隔中第一个间隔的位置最准确,然后将第二个间隔向右移动。一个相关的问题是,如果移动一个间隔,则使其与另一个间隔重叠在右边等等,然后间隔将继续向右移动。但是,我希望更精确,通过向左和向右移动,尽可能保持原始位置。