Reputation: 708
I'm looking for an easy way to find the minimum distance between two integer intervals using python. For example, the minimum between [0,10] and [12,20] would be 2. If the two intervals overlap in any way, the distance would be 0.
Any suggestions on an easy way to do this? I can't help but think there must be a clean, 'pythonic' way to get at this question.
Upvotes: 5
Views: 3159
Reputation: 360
Doesn't really depend on the programming language:
if (EndA < StartA || EndB < StartA) # check for malformed intervals
return 0;
return max(0, StartA - EndB, StartB - EndA)
(This assumes the intervals are closed. If the intervals are open, you need to adjust the check for malformed intervals accordingly.)
The other answers lack justification for their formulas, so let me give one:
Let the two intervals be [startA, endA]
and [startB, endB]
. The two intervals overlap if
(StartA <= EndB) and (StartB <= EndA)
Since we are only interested in the case where there is no overlap, we take the negation of that condition
(StartA > EndB) or (StartB > EndA)
Now if StartA > EndB
, then the first interval lies to the right of the first, so their distance is startA - endB
. Conversely, if StartB > EndA
, the first lies to the left of the second, so their distance is startB - endA
.
Taken together we get
if (StartA > EndB):
return StartA - EndB
if (StartB > EndA):
return StartB - EndA
return 0
Now consider that (a) for valid intervals (i.e. EndA >= StartA
and EndB >= StartB
), either one of StartA - EndB
or StartB - EndA
will be negative if there is no overlap*, and that (b) for overlapping ranges both StartA - EndB
and StartB - EndA
will be non-positive**. Then you can shorten this to:
max(0, StartA - EndB, StartB - EndA)
As for invalid intervals: If an interval is invalid and we define that to mean an empty interval, i.e. as an empty set without any elements, and we further define the distance between two intervals as the length of the smallest interval that can be added so that it together with both intervals forms a single continuous interval, then the distance between an invalid interval and another interval is 0 (as the second interval already forms a single continuous interval, so we only need to add an empty interval, which has length 0).
(*) If e.g. the first interval lies to the right of the second, it follows that
StartA > EndB // assuming first interval lies to the right of the second
EndA >= StartA // assuming first interval is valid
EndB >= StartB // assuming first interval is valid
EndA >= StartA > EndB >= StartB // combine the inequalities
EndA > StartB // shorten
StartB - EndA < 0 // so the other quantity is negative
(**) Since for overlapping ranges we have StartA <= EndB
and StartB <= EndA
, it follows that StartA - EndB <= 0
and StartB - EndA <= 0
Upvotes: 0
Reputation: 250891
def solve(r1, r2):
# sort the two ranges such that the range with smaller first element
# is assigned to x and the bigger one is assigned to y
x, y = sorted((r1, r2))
#now if x[1] lies between x[0] and y[0](x[1] != y[0] but can be equal to x[0])
#then the ranges are not overlapping and return the differnce of y[0] and x[1]
#otherwise return 0
if x[0] <= x[1] < y[0] and all( y[0] <= y[1] for y in (r1,r2)):
return y[0] - x[1]
return 0
...
>>> solve([0,10],[12,20])
2
>>> solve([5,10],[1,5])
0
>>> solve([5,10],[1,4])
1
Upvotes: 6
Reputation: 1
Hopefully the following helps:
def myDist(a,b):
if a[0] <= a[1] < b[0]:
return b[0] - a[1]
if b[0] <= b[1] < a[0]:
return a[0] - b[1]
return 0
Good Luck!!!
Upvotes: 0