I want to input a list of intervals and check the intervals of the union of overlapping intervals and the intervals of non-overlapping intervals
Question:
For example: I have the intervals = [[-5,-3],[-4,-1],[1,3],[4,8],[5,10],[10,12], [15,20]]
(not necessaraly sorted like that)
I want the function to return me [[-5,-1],[1,3],[4,12],[15,20]]
. Since [-5,-3],[-4,-1] and [4,8],[5,10],[10,12]
have numbers that intercept each other. I.e., I want the function to return all the "lonely" intervals and the min’s and max’s of the union of the intervals in which their numbers intercept each other.
I have this code that do something similar, but it isn’t what I want yet:
def maxDisjointIntervals(list_):
# Lambda function to sort the list
# elements by second element of pairs
list_.sort(key = lambda x: x[1])
# First interval will always be
# included in set
print("[", list_[0][0], ", ", list_[0][1], "]")
# End point of first interval
r1 = list_[0][1]
for i in range(1, len(list_)):
l1 = list_[i][0]
r2 = list_[i][1]
# Check if given interval overlap with
# previously included interval, if not
# then include this interval and update
# the end point of last added interval
if l1 > r1:
print("[", l1, ", ", r2, "]")
r1 = r2
This code is returning me this output: [[-5, -3],[1, 3],[4, 8],[10, 12],[15, 20]]
repeating what I said before: I want it to return me this output [[-5, -1],[1, 3],[4, 12],[15, 20]]
I hope my explanation didn’t turned out to be too prolix since I’m not a native english speaker. Thanks!
Answers:
So what I understand is that you would like to find intervals which are connected or overlapped, you may do that by using an iterator.
def maxDisjointIntervals(intervals): # dont use list_ as your variable name
overlappedIntervals = []
if len(intervals) == 0:
return overlappedIntervals
# sort the intervals using the starting time
intervals = sorted(intervals, key=lambda interval: interval[0])
# init the start hour and end hour
startHour = intervals[0][0]
endHour = intervals[0][1]
for interval in intervals[1:]:
# if there is an overlap
if interval[0] <= endHour <= interval[1]:
endHour = interval[1]
# if there is not an overlap
else:
overlappedIntervals.append([startHour, endHour])
startHour = interval[0]
endHour = interval[1]
overlappedIntervals.append([startHour, endHour])
return overlappedIntervals
print(maxDisjointIntervals([[-5, -3], [-4, -1], [1, 3], [4, 8], [5, 10], [10, 12], [13, 20]]))
output: [[-5, -1], [1, 3], [4, 12], [13, 20]]
You can use reduce from functools to merge the intervals together:
intervals = [[-5,-3],[-4,-1],[1,3],[4,8],[5,10],[10,12], [15,20]]
from functools import reduce
disjoints = [*reduce(lambda a,b: a+[b] if not a or b[0]>a[-1][1] else a[:-1]+[[a[-1][0],b[1]]],intervals,[])]
print(disjoints) # [[-5, -1], [1, 3], [4, 12], [15, 20]]
or do the same thing in a basic loop:
disjoints = intervals[:1]
for s,e in intervals[1:]:
if s>disjoints[-1][-1]: disjoints.append([s,e])
else: disjoints[-1][-1] = e
print(disjoints) # [[-5, -1], [1, 3], [4, 12], [15, 20]]
note: this assumes inclusive ranges. If the end is exclusive use >=
instead of >
.
I think the code should be updated to:
for s,e in intervals[1:]:
if s > disjoints[-1][-1]:
disjoints.append([s,e])
elif e > disjoints[-1][-1]:
disjoints[-1][-1] = e
otherwise it will fail for this case:
intervals = [[-5,-3],[-4,-1],[1,3],**[4,8],[5,7]**,[10,12], [15,20]]
The answer was:
[[-5, -1], [1, 3], [4, **7], [10**, 12], [15, 20]]
instead of:
[[-5, -1], [1, 3], [4, **8], [10**, 12], [15, 20]]
For example: I have the intervals = [[-5,-3],[-4,-1],[1,3],[4,8],[5,10],[10,12], [15,20]]
(not necessaraly sorted like that)
I want the function to return me [[-5,-1],[1,3],[4,12],[15,20]]
. Since [-5,-3],[-4,-1] and [4,8],[5,10],[10,12]
have numbers that intercept each other. I.e., I want the function to return all the "lonely" intervals and the min’s and max’s of the union of the intervals in which their numbers intercept each other.
I have this code that do something similar, but it isn’t what I want yet:
def maxDisjointIntervals(list_):
# Lambda function to sort the list
# elements by second element of pairs
list_.sort(key = lambda x: x[1])
# First interval will always be
# included in set
print("[", list_[0][0], ", ", list_[0][1], "]")
# End point of first interval
r1 = list_[0][1]
for i in range(1, len(list_)):
l1 = list_[i][0]
r2 = list_[i][1]
# Check if given interval overlap with
# previously included interval, if not
# then include this interval and update
# the end point of last added interval
if l1 > r1:
print("[", l1, ", ", r2, "]")
r1 = r2
This code is returning me this output: [[-5, -3],[1, 3],[4, 8],[10, 12],[15, 20]]
repeating what I said before: I want it to return me this output [[-5, -1],[1, 3],[4, 12],[15, 20]]
I hope my explanation didn’t turned out to be too prolix since I’m not a native english speaker. Thanks!
So what I understand is that you would like to find intervals which are connected or overlapped, you may do that by using an iterator.
def maxDisjointIntervals(intervals): # dont use list_ as your variable name
overlappedIntervals = []
if len(intervals) == 0:
return overlappedIntervals
# sort the intervals using the starting time
intervals = sorted(intervals, key=lambda interval: interval[0])
# init the start hour and end hour
startHour = intervals[0][0]
endHour = intervals[0][1]
for interval in intervals[1:]:
# if there is an overlap
if interval[0] <= endHour <= interval[1]:
endHour = interval[1]
# if there is not an overlap
else:
overlappedIntervals.append([startHour, endHour])
startHour = interval[0]
endHour = interval[1]
overlappedIntervals.append([startHour, endHour])
return overlappedIntervals
print(maxDisjointIntervals([[-5, -3], [-4, -1], [1, 3], [4, 8], [5, 10], [10, 12], [13, 20]]))
output: [[-5, -1], [1, 3], [4, 12], [13, 20]]
You can use reduce from functools to merge the intervals together:
intervals = [[-5,-3],[-4,-1],[1,3],[4,8],[5,10],[10,12], [15,20]]
from functools import reduce
disjoints = [*reduce(lambda a,b: a+[b] if not a or b[0]>a[-1][1] else a[:-1]+[[a[-1][0],b[1]]],intervals,[])]
print(disjoints) # [[-5, -1], [1, 3], [4, 12], [15, 20]]
or do the same thing in a basic loop:
disjoints = intervals[:1]
for s,e in intervals[1:]:
if s>disjoints[-1][-1]: disjoints.append([s,e])
else: disjoints[-1][-1] = e
print(disjoints) # [[-5, -1], [1, 3], [4, 12], [15, 20]]
note: this assumes inclusive ranges. If the end is exclusive use >=
instead of >
.
I think the code should be updated to:
for s,e in intervals[1:]:
if s > disjoints[-1][-1]:
disjoints.append([s,e])
elif e > disjoints[-1][-1]:
disjoints[-1][-1] = e
otherwise it will fail for this case:
intervals = [[-5,-3],[-4,-1],[1,3],**[4,8],[5,7]**,[10,12], [15,20]]
The answer was:
[[-5, -1], [1, 3], [4, **7], [10**, 12], [15, 20]]
instead of:
[[-5, -1], [1, 3], [4, **8], [10**, 12], [15, 20]]