Reputation:
is there a built in function to compute the overlap between two discrete intervals, e.g. the overlap between [10, 15] and [20, 38]? In that case the overlap is 0. If it's [10, 20], [15, 20], the overlap is 5.
Upvotes: 39
Views: 42116
Reputation: 60
Not the way I would ordinarily do this, but it shows the work and explains the assumptions and how it operates, and shows all the work.
def getOverlap(a:list, b:list)->int:
# Assumptions are:
# both a and b are a 2-element list/vector
# each element of each list is an integer
# each list defines a range with a starting and ending point
# There is no requirement that the starting point be greater than the ending point
#
# Returns the _number_ of common elements that exist in both ranges
# the input lists (a and b) are unmodified
#
# Function first sorts each tuple
# then it uses the sorted tuples to make the calculation,
# which means element 0 is lower than element 1 in each tuple
# the elements of each tuple can be accessed by its index (0, or 1)
# the min() and max() functions are used to extract either the
# minimum or the maximum of (here, a pair) of values
# the difference between the resulting min and max (plus 1) yields
# the number of common elements that exist in both ranges
# (if this number is negative, then there are no common elements)
# it then applies the max function to return the proper answer
#
sa = sorted(a)
sb = sorted(b)
lowest_endpoint = min(sa[1], sb[1])
highest_origin = max(sa[0], sb[0])
number_of_common_elements = lowest_endpoint - highest_origin + 1
return max(0, number_of_common_elements)
or, more simply:
def getOverlap(a:list, b:list)->int:
sa = sorted(a)
sb = sorted(b)
return max(0, min(sa[1], sb[1]) - max(sa[0], sb[0]) + 1)
Upvotes: 0
Reputation: 44
def Overlap(self, R1, R2):
if (A1[0]>=A2[2]) or (A1[2]<=A2[0]) or (A1[3]<=A2[1]) or (A1[1]>=A2[3]):
return False
else:
return True
ob = Solution()
print(ob.Overlap([0,0,2,2],[1,1,3,3]))
Upvotes: -2
Reputation: 5261
Did some more checks to clarify behaviour & correctness:
def get_intersection_overlap(a, b):
"""
Returns the intersection over union of two bounding boxes.
Note, lower and upper bounds intersect exactly, it is considered not an intersection.
ref:
- https://stackoverflow.com/a/2953979/1601580
"""
return max(0, min(a[1], b[1]) - max(a[0], b[0]))
def get_intersection_overlap_care_about_exact_match(a, b):
"""
Return the amount of overlap, in bp
between a and b.
If >0, the number of bp of overlap
If 0, they are book-ended.
If <0, the distance in bp between them
ref:
- https://stackoverflow.com/a/52388579/1601580
"""
return min(a[1], b[1]) - max(a[0], b[0])
tests
def overlap_intersection_test():
"""
want to test if two intervals intersect/overlap and return true if they do
"""
print('----')
print(f'{get_intersection_overlap([10, 25], [20, 38])}')
assert get_intersection_overlap([10, 25], [20, 38]) == 5
print(f'{get_intersection_overlap([20, 38], [10, 25])}')
assert get_intersection_overlap([20, 38], [10, 25]) == 5
print(f'{get_intersection_overlap([10, 15], [20, 38])}')
assert get_intersection_overlap([10, 15], [20, 38]) == 0
print(f'{get_intersection_overlap([10, 15], [20, 38])}')
assert get_intersection_overlap([10, 15], [20, 38]) == 0
print(f'{get_intersection_overlap([10, 15], [15, 38])}')
assert get_intersection_overlap([10, 15], [15, 38]) == 0
# -
print('----')
print(f'{get_intersection_overlap_care_about_exact_match([10, 25], [20, 38])}')
assert get_intersection_overlap_care_about_exact_match([10, 25], [20, 38]) == 5
print(f'{get_intersection_overlap_care_about_exact_match([20, 38], [10, 25])}')
assert get_intersection_overlap_care_about_exact_match([20, 38], [10, 25]) == 5
print(f'{get_intersection_overlap_care_about_exact_match([10, 15], [20, 38])}')
assert get_intersection_overlap_care_about_exact_match([10, 15], [20, 38]) == -5
print(f'{get_intersection_overlap_care_about_exact_match([10, 15], [20, 38])}')
assert get_intersection_overlap_care_about_exact_match([10, 15], [20, 38]) == -5
print(f'{get_intersection_overlap_care_about_exact_match([10, 15], [15, 38])}')
assert get_intersection_overlap_care_about_exact_match([10, 15], [15, 38]) == 0
output:
----
5
5
0
0
0
----
5
5
-5
-5
0
Upvotes: 0
Reputation: 683
I had to process inclusive bounds so the current answers did not work. Here is a solution with inclusive bounds if you only care about a True/False answer:
def overlap(first: int, last: int, another_first: int, another_last: int)->bool:
"""
Return True if the two intervals overlap.
>>> not any([
... _overlap(1, 1, 2, 2),
... _overlap(2, 2, 1, 1)
... ])
True
>>> all([
... _overlap(1, 1, 1, 1),
... _overlap(1, 5, 1, 1),
... _overlap(1, 1, 1, 5),
... _overlap(1, 3, 2, 5),
... _overlap(2, 5, 1, 3),
... _overlap(1, 5, 2, 3),
... _overlap(2, 3, 1, 5),
... ])
True
"""
return min(last, another_last) - max(first, another_first) >= 0
Upvotes: 2
Reputation: 1491
Just wrote this:
def overlap(interval1, interval2):
"""
Given [0, 4] and [1, 10] returns [1, 4]
"""
if interval2[0] <= interval1[0] <= interval2[1]:
start = interval1[0]
elif interval1[0] <= interval2[0] <= interval1[1]:
start = interval2[0]
else:
raise Exception("Intervals are not overlapping")
if interval2[0] <= interval1[1] <= interval2[1]:
end = interval1[1]
elif interval1[0] <= interval2[1] <= interval1[1]:
end = interval2[1]
else:
raise Exception("Intervals are not overlapping")
return (start, end)
def percentage_overlap(interval1, interval2):
"""
Given [0, 4] and [1, 10] returns 0.75
"""
try:
overlap = _overlap(interval1, interval2)
except Exception:
return 0.0
return (overlap[1] - overlap[0]) / (interval1[1] - interval1[0])
Upvotes: 2
Reputation: 31918
Here is a good function from Aaron Quinlan's chrom_sweep, modified for your interval representation. It returns the number of bp of overlap if they do overlap, otherwise it returns the distance as a negative int.
def overlaps(a, b):
"""
Return the amount of overlap, in bp
between a and b.
If >0, the number of bp of overlap
If 0, they are book-ended.
If <0, the distance in bp between them
"""
return min(a[1], b[1]) - max(a[0], b[0])
Upvotes: 4
Reputation: 838206
You can use max and min:
>>> def getOverlap(a, b):
... return max(0, min(a[1], b[1]) - max(a[0], b[0]))
>>> getOverlap([10, 25], [20, 38])
5
>>> getOverlap([10, 15], [20, 38])
0
Upvotes: 93
Reputation: 879481
Check out pyinterval http://code.google.com/p/pyinterval/
import interval
x=interval.interval[10, 15]
y=interval.interval[20, 38]
z=interval.interval[12,18]
print(x & y)
# interval()
print(x & z)
# interval([12.0, 15.0])
Upvotes: 17