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.
            Asked
            
        
        
            Active
            
        
            Viewed 3.9k times
        
    38
            
            
        - 
                    Do you mean that if you want the overlap between [10,25] and [20,38], that the result should be [20,25]? – Marc Jun 01 '10 at 23:06
 - 
                    What do you mean overlap? Please give an example of the expected result. – Chinmay Kanchi Jun 01 '10 at 23:06
 - 
                    3there is overlap between [10,15] and [20,38]? – joaquin Jun 01 '10 at 23:07
 - 
                    1why is the overlap of [10, 20] and [15, 20] 5 and not 6? there are 6 values that overlap in those two intervals (15, 16, 17, 18, 19, and 20). if they are exclusive intervals rather than inclusive, then there are 4 overlapping values (16, 17, 18, and 19). – Dave Cousineau Mar 27 '15 at 22:46
 - 
                    @Marc if one wants [20,25] what is the best way to do it? please point me to any similar questions. I'm trying to achieve exactly this ^ – DJ_Stuffy_K Mar 06 '18 at 18:21
 - 
                    can the answers elaborate why they are correct? e.g. what is a and what is b and what is indexing 0 or 1 doing. Why the mins & maxes etc. – Charlie Parker Jan 24 '23 at 21:23
 
8 Answers
90
            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
        Mark Byers
        
- 811,555
 - 193
 - 1,581
 - 1,452
 
- 
                    1unless the intervals are implied to be exclusive on the first value and inclusive on the second (or something like that...), this would need a `+ 1` to the subtraction. – Dave Cousineau Mar 27 '15 at 23:06
 - 
                    thanks for the answer, how would I go about finding the `percentage overlap` between those ranges? – DJ_Stuffy_K Mar 06 '18 at 19:10
 - 
                    @DJ_Stuffy_K for percentage overlap, see mine answer below. Hope it helps. – jhutar Apr 07 '19 at 21:33
 - 
                    
 - 
                    @CharlieParker in the function Mark made, a and b can be lists or tuples of length 2. They are your given intervals, for example, when calculating the intervals of [10, 20] and [15, 25], a could be [10, 20] and b would be [15, 25]. In this case, a[0] = 10, a[1] = 20, b[0] = 15, b[1] = 25. – Hans VK Jan 31 '23 at 14:36
 - 
                    @CharlieParker In this case, we could just say that the answer is equivalent to "return a[1] - b[0]", which returns 5 in our case. Mark's answer also covered 2 different scenarios: 1) the first interval is the larger interval. -- min(a[1], b[1]) - max(a[0], b[0]) will get us the right interval overlap, unless: 2) there is no overlap -- max(0, min(a[1], b[1]) - max(a[0], b[0])) ensures the overlap is never negative. – Hans VK Jan 31 '23 at 15:00
 
17
            
            
        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])
        unutbu
        
- 842,883
 - 184
 - 1,785
 - 1,677
 
- 
                    2+1 Because I didn't know about that module, though it might be overkill if he just needs it for this one calculation. – Mark Byers Jun 01 '10 at 23:15
 - 
                    2
 - 
                    I think although the documentation is the same, the module has changed slightly. The `interval` object does not have any attribute named `interval`anymore... – T-800 Aug 01 '14 at 13:41
 - 
                    @T-1000: When you `import interval`, `interval` refers to the module. `interval.interval` refers to the `interval` class. In contrast, when you use `from interval import interval`, then `interval` refers to the class. In neither case is there any reference to an `interval` attribute. – unutbu Aug 01 '14 at 14:11
 - 
                    @unutbu Thanks for your explanation. I think there is very similar module called `interval`. I have installed using `pip install interval` and the codes you provided did not function. Then I tried to install `pip install pyinterval` but, I got "Could not find a version that satisfies the requirement pyinterval (from versions: 1.0b14, 1.0b21)" error. What can be going wrong? I couldn't find any documentation about requirements... – T-800 Aug 01 '14 at 14:18
 - 
                    1@T-1000: Yes, the procedure I used to install it a while back no longer works. Per the instructions [here](https://pypi.python.org/pypi/pyinterval/) you might try `easy_install pyinterval`. Or, I believe you'll need to install [crlibm](http://lipforge.ens-lyon.fr/www/crlibm/download.html), and then download the tar file from the same page and try `python setup.py install`. – unutbu Aug 01 '14 at 14:59
 - 
                    
 - 
                    It's really fine because it makes possible to check more intervals (not just 2). – szabozoltan Feb 14 '19 at 07:55
 
4
            
            
        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])
        The Unfun Cat
        
- 29,987
 - 31
 - 114
 - 156
 
- 
                    2This seems to be the same as Mark Byers answer from 8 years ago, except that I don't know what bp means (and I would say "adjacent" instead of "book ended"). – Teepeemm Nov 07 '18 at 21:53
 - 
                    
 - 
                    
 - 
                    
 
2
            
            
        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])
        jhutar
        
- 1,369
 - 2
 - 17
 - 32
 
2
            
            
        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
        marko.ristin
        
- 643
 - 8
 - 6
 
0
            
            
        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
        Charlie Parker
        
- 5,884
 - 57
 - 198
 - 323
 
0
            
            
        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)
        cteljr
        
- 25
 - 4
 
-2
            
            
        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]))
        Gino Mempin
        
- 25,369
 - 29
 - 96
 - 135
 
        Saurabh Sharma
        
- 52
 - 5