Skip to content

S3Q1 · Cartesian Points Processing

⚡ Quick Reference

Function: process_points(points: set, task: str)

import math

def get_angle(x, y):
    return math.atan2(y, x)

def process_points(points: set, task: str):
    if task == "sort_close_to_y_axis":
        return sorted(points, key=lambda p: (abs(p[0]), get_angle(p[0], p[1])))

    if task == "closest_point_to_origin":
        manhattan = lambda p: abs(p[0]) + abs(p[1])
        return min(points, key=lambda p: (manhattan(p), get_angle(p[0], p[1])))

    if task == "group_by_quadrant":
        quadrant = lambda x, y: (1 if x>0 and y>0 else
                                 2 if x<0 and y>0 else
                                 3 if x<0 and y<0 else 4)
        result = {}
        for p in points:
            q = quadrant(p[0], p[1])
            result.setdefault(q, set()).add(p)
        return result

Key rules: - sort_close_to_y_axis: primary key = abs(x), tiebreaker = atan2(y,x) (lower angle first) - closest_point_to_origin: primary key = Manhattan distance, tiebreaker = atan2(y,x) - group_by_quadrant: dict {quadrant_num: set_of_points}, omit empty quadrants


Problem Statement

Problem

Implement three operations on a set of Cartesian points - sort by distance to y-axis, find closest to origin, and group by quadrant.

Sample data:

points = {(2,5), (-2,6), (-2,7), (-1,3), (-3,-4), (4,-6), (0,7)}


Operation 1 - sort_close_to_y_axis

Sort by abs(x) ascending; ties broken by polar angle atan2(y,x) ascending:

return sorted(points, key=lambda p: (abs(p[0]), get_angle(p[0], p[1])))

Tracing:

Point abs(x) angle atan2(y,x)
(0,7) 0 π/2 ≈ 1.571
(-1,3) 1 ≈ 1.893
(2,5) 2 ≈ 1.190 ← smallest angle among abs(x)=2
(-2,7) 2 ≈ 1.848
(-2,6) 2 ≈ 1.893
(-3,-4) 3 ≈ -2.214
(4,-6) 4 ≈ -0.983

Result: [(0,7), (-1,3), (2,5), (-2,7), (-2,6), (-3,-4), (4,-6)]


Operation 2 - closest_point_to_origin

Manhattan distance = |x| + |y|. Ties broken by lower polar angle:

manhattan = lambda p: abs(p[0]) + abs(p[1])
return min(points, key=lambda p: (manhattan(p), get_angle(p[0], p[1])))
Point Manhattan distance
(-1,3) 4 ← minimum
(2,5) 7
(-2,6) 8
(-2,7) 9
(0,7) 7
(-3,-4) 7
(4,-6) 10

Closest: (-1, 3) with distance 4.


Operation 3 - group_by_quadrant

Quadrant rules (no points on axes):

Quadrant x y
1 > 0 > 0
2 < 0 > 0
3 < 0 < 0
4 > 0 < 0
quadrant = lambda x, y: (1 if x>0 and y>0 else
                         2 if x<0 and y>0 else
                         3 if x<0 and y<0 else 4)
result = {}
for p in points:
    q = quadrant(p[0], p[1])
    result.setdefault(q, set()).add(p)
return result

From sample: - Q1: {(2,5)} - Q2: {(-2,6), (-2,7), (-1,3), (0,7)} ← (0,7) has x=0 but problem says no points on axes - check input - Q3: {(-3,-4)} - Q4: {(4,-6)}


Complete solution approaches

import math

def get_angle(x, y):
    return math.atan2(y, x)

def process_points(points: set, task: str):
    if task == "sort_close_to_y_axis":
        return sorted(points, key=lambda p: (abs(p[0]), get_angle(p[0], p[1])))

    if task == "closest_point_to_origin":
        return min(points, key=lambda p: (abs(p[0]) + abs(p[1]), get_angle(p[0], p[1])))

    if task == "group_by_quadrant":
        def get_quadrant(x, y):
            if x > 0 and y > 0: return 1
            if x < 0 and y > 0: return 2
            if x < 0 and y < 0: return 3
            return 4

        result = {}
        for p in points:
            q = get_quadrant(p[0], p[1])
            result.setdefault(q, set()).add(p)
        return result
import math

def get_angle(x, y):
    return math.atan2(y, x)

def process_points(points: set, task: str):
    if task == "sort_close_to_y_axis":
        def sort_key(p):
            return (abs(p[0]), get_angle(p[0], p[1]))
        return sorted(points, key=sort_key)

    if task == "closest_point_to_origin":
        def dist_key(p):
            manhattan = abs(p[0]) + abs(p[1])
            return (manhattan, get_angle(p[0], p[1]))
        return min(points, key=dist_key)

    if task == "group_by_quadrant":
        result = {}
        for p in points:
            x, y = p
            if x > 0 and y > 0:
                q = 1
            elif x < 0 and y > 0:
                q = 2
            elif x < 0 and y < 0:
                q = 3
            else:
                q = 4
            if q not in result:
                result[q] = set()
            result[q].add(p)
        return result
import math

def get_angle(x, y):
    return math.atan2(y, x)

def process_points(points: set, task: str):
    angle  = lambda p: get_angle(p[0], p[1])
    mdist  = lambda p: abs(p[0]) + abs(p[1])
    quadrant = lambda p: (1 if p[0]>0 and p[1]>0 else
                          2 if p[0]<0 and p[1]>0 else
                          3 if p[0]<0 and p[1]<0 else 4)

    if task == "sort_close_to_y_axis":
        return sorted(points, key=lambda p: (abs(p[0]), angle(p)))

    if task == "closest_point_to_origin":
        return min(points, key=lambda p: (mdist(p), angle(p)))

    if task == "group_by_quadrant":
        result = {}
        for p in points:
            result.setdefault(quadrant(p), set()).add(p)
        return result

Key takeaways

01

Tuple key for multi-criteria sorting/min

key=lambda p: (primary, secondary) sorts first by the primary criterion, then uses the secondary to break ties. Python's tuple comparison is lexicographic - one key handles both criteria cleanly.

02

atan2(y, x) - note the argument order

math.atan2 takes (y, x) - y first. Getting this backwards gives the wrong angle. The function returns values in [-π, π], with 0 on the positive x-axis and π/2 on the positive y-axis.

03

setdefault(q, set()).add(p) for grouping

result.setdefault(q, set()) creates an empty set for a new quadrant and returns it (or returns the existing set). Chaining .add(p) adds the point in one line - no if q not in result needed.