So I am trying to write a piece of code so it takes a list of points rather than a single point and returns boolean True only if all points in the list are in the rectangle.
For example,
allIn((0,0), (5,5), [(1,1), (0,0), (5,5)]) should return True
but allIn((0,0), (5,5), [(1,1), (0,0), (5,6)]) should return False
empty list of points allIn((0,0), (5,5), []) should return False
I can't seem to get the return to match the above example for both false returns.The empty list should return false. Any idea where I am going wrong?
def allIn(firstCorner=(0,0), secondCorner=(0,0), pointList=[]):
x1 = firstCorner[0]
y1 = firstCorner[1]
x2 = secondCorner[0]
y2 = secondCorner[1]
for i in range(len(pointList)):
p_x = pointList[i][0]
p_y = pointList[i][1]
if not ((p_x >= x1 and p_x < x2) and (p_y >= y1 and p_y < y2)):
return False
return True
print(allIn((0,0), (5,5), [(1,1), (0,0), (5,5)]))
print(allIn((0,0), (5,5), [(1,1), (0,0), (5,6)]))
print(allIn((0,0), (5,5), []))
CodePudding user response:
In order to fix the issue, you have to change the if statement to be nested in the for loop you have above. Otherwise, the statement doesn't check every single point of the list but only the last one.
Moreover, if you want your first example of yours to be true you have to check whether the point is less or equal to the secondCorner.
You can also add one more if statement in order to check if the list is empty in order to return false as you would like in the last example of yours.
if not(pointList):
return False
for i in range(len(pointList)):
p_x = pointList[i][0]
p_y = pointList[i][1]
if not ((p_x >= x1 and p_x <= x2) and (p_y >= y1 and p_y <= y2)):
return False
return True
CodePudding user response:
Two things:
- You only return
False
inside the loop. If the loop never runs (which is the case if the list of points is empty), you will always return true. ((p_x >= x1 and p_x < x2) and (p_y >= y1 and p_y < y2))
should be((p_x >= x1 and p_x <= x2) and (p_y >= y1 and p_y <= y2))
(end coordinates of rectangle should be inclusive, rather than exclusive.)
I would recommend defining one function that determines whether a single point is within a rectangle, then reuse that function to check if all points are within a rectangle:
from collections import namedtuple
def point_in_rect(point, rect):
return (rect.first.x <= point.x <= rect.second.x) and (rect.first.y <= point.y <= rect.second.y)
def points_in_rect(points, rect):
return bool(points) and all(point_in_rect(point, rect) for point in points)
Point = namedtuple("Point", "x y")
Rectangle = namedtuple("Rectangle", "first second")
rect = Rectangle(Point(0, 0), Point(5, 5))
print(points_in_rect([Point(1, 1), Point(0, 0), Point(5, 5)], rect)) # True
print(points_in_rect([Point(1, 1), Point(0, 0), Point(5, 6)], rect)) # False
print(points_in_rect([], rect)) # False
CodePudding user response:
Just adding another option to the list. You could use numpy here as well, avoiding a for loop.
import numpy as np
def allIn(firstCorner=(0,0), secondCorner=(0,0), pointList=[]):
# list is empty, return False
if not pointList:
return False
arr = np.array(pointList)
return False not in (arr >= firstCorner) & (arr <= secondCorner)
print(allIn((0,0), (5,5), [(1,1), (0,0), (5,5)])) # True
print(allIn((0,0), (5,5), [(1,1), (0,0), (5,6)])) # False
print(allIn((0,0), (5,5), [])) # False
E.g. for [(1,1), (0,0), (5,6)]
, the array becomes:
[[1 1]
[0 0]
[5 6]]
which is turned into:
[[ True True]
[ True True]
[ True False]]
# i.e. 6 is out of bounds, creating 1 False in the array, returning False for the function.