patternpythonModerate
Overlapping rectangles
Viewed 0 times
overlappingrectanglesstackoverflow
Problem
I received the following question in a technical interview today (for a devops/SRE position):
Write a function which returns true if the two rectangles passed to it
as arguments would overlap if drawn on a Cartesian plane. The
rectangles are guaranteed to be aligned with the axes, not arbitrarily
rotated.
I pretty much blew the whole thought process for how to approach the question I wasn't thinking of cases where, for example, one rectangle might be enclosed entirely within the other or of cases where a short wide rectangle might cross wholly through a taller, narrower one forming some sort of cross --- so I was off on a non-productive tangent thinking about whether any corner of either rectangle was within the bounding box of the other.
Naturally as soon as I got home, having let the problem settle more in my mind, I was able to write something which seems reasonably elegant and seems to work (for the test cases I've tried so far).
This graphic (which took far longer to create than the code, and I don't even know how to make Inkscape show the gridlines in the saved image as it's showing in my working canvas) shows the simplest obvious cases: red/aqua overlapping by a corner, blue completely enclosing fuschia and green/yellow overlapping but without any corner enclosed within the other. My test code uses red/blue, blue/green and similar combinations as the non-overlapping test cases, including those which would overlap only in horizontal or vertical dimensions but are clear in the other dimension.
My thought process, when I got home and sat down with a keyboard was as follows:
We only care about edges, ultimately. So my
For rectangles to overlap there must be some overlap in both the horizontal and vertical directions. So it should be sufficient to just test if either the left or right edge of the first rectangle argument is to the right
Write a function which returns true if the two rectangles passed to it
as arguments would overlap if drawn on a Cartesian plane. The
rectangles are guaranteed to be aligned with the axes, not arbitrarily
rotated.
I pretty much blew the whole thought process for how to approach the question I wasn't thinking of cases where, for example, one rectangle might be enclosed entirely within the other or of cases where a short wide rectangle might cross wholly through a taller, narrower one forming some sort of cross --- so I was off on a non-productive tangent thinking about whether any corner of either rectangle was within the bounding box of the other.
Naturally as soon as I got home, having let the problem settle more in my mind, I was able to write something which seems reasonably elegant and seems to work (for the test cases I've tried so far).
This graphic (which took far longer to create than the code, and I don't even know how to make Inkscape show the gridlines in the saved image as it's showing in my working canvas) shows the simplest obvious cases: red/aqua overlapping by a corner, blue completely enclosing fuschia and green/yellow overlapping but without any corner enclosed within the other. My test code uses red/blue, blue/green and similar combinations as the non-overlapping test cases, including those which would overlap only in horizontal or vertical dimensions but are clear in the other dimension.
My thought process, when I got home and sat down with a keyboard was as follows:
We only care about edges, ultimately. So my
Rect() class store just the X scalar of the left and right edges, and the Y scalar of top and bottom edges.For rectangles to overlap there must be some overlap in both the horizontal and vertical directions. So it should be sufficient to just test if either the left or right edge of the first rectangle argument is to the right
Solution
You have common code, which moreover has applications beyond this one, so should you not pull it out into a function? Then you can reduce
Now, the key condition encapsulated by
overlap todef overlap(r1, r2):
'''Overlapping rectangles overlap both horizontally & vertically
'''
return range_overlap(r1.left, r1.right, r2.left, r2.right) and range_overlap(r1.bottom, r1.top, r2.bottom, r2.top)
Now, the key condition encapsulated by
range_overlap is that neither range is completely greater than the other. A direct refactor of the way you've expressed this isdef range_overlap(a_min, a_max, b_min, b_max):
'''Neither range is completely greater than the other
'''
overlapping = True
if (a_min > b_max) or (a_max
For such a simple condition I would prefer to use not rather than if-else assignment. I would also reorder the second condition to exhibit the symmetry more clearly:
def range_overlap(a_min, a_max, b_min, b_max):
'''Neither range is completely greater than the other
'''
return not ((a_min > b_max) or (b_min > a_max))
Of course, de Morgan's laws allow rewriting as
def range_overlap(a_min, a_max, b_min, b_max):
'''Neither range is completely greater than the other
'''
return (a_min <= b_max) and (b_min <= a_max)
I think that the last of these is the most transparent, but that's an issue of aesthetics and you may disagree.
Note that I've assumed throughout, as you do, that the rectangles are closed (i.e. that they contain their edges). To make them open, change > to >= and <= to <`.Code Snippets
def range_overlap(a_min, a_max, b_min, b_max):
'''Neither range is completely greater than the other
'''
return not ((a_min > b_max) or (b_min > a_max))def range_overlap(a_min, a_max, b_min, b_max):
'''Neither range is completely greater than the other
'''
return (a_min <= b_max) and (b_min <= a_max)Context
StackExchange Code Review Q#31352, answer score: 18
Revisions (0)
No revisions yet.