Juan Castaño
Juan Castaño

Reputation: 67

How to order coordinates from top left to bottom right?

I have a list of class objects my_rectangle:

class my_rectangle:
    def __init__(self,text,x_start,y_start,x_end,y_end):
        self.text=text
        self.x_start=x_start
        self.y_start=y_start
        self.x_end=x_end
        self.y_end=y_end
        self.x_centroid=(self.x_start+self.x_end)/2
        self.y_centroid=(self.y_start+self.y_end)/2

Using the class attributes (x_centroid and y_centroid) which give the coordinates of the centroid, I wanted to order this list, using as an order left-to-right then top-to-bottom (normal English reading order)?

Say I have:

A=my_rectangle('Hi,',1,3,2,4)
B=my_rectangle('Im',3,3,3,4)
C=my_rectangle('New',1,1,2,2)
my_list=[C,B,A]

And I want to order it to get:

my_sorted_list=[A,B,C]

Which is a representation of the text:

""" Hi, I'm
    New 
"""

Upvotes: 2

Views: 5214

Answers (2)

Håken Lid
Håken Lid

Reputation: 23064

You can make custom classes sortable by defining a __lt__ method. This takes care of the < operator which is used in default sorting.

class Rectangle:
    def __init__(self,text,x_start,y_start,x_end,y_end):
        self.text=text
        self.x_start=x_start
        self.y_start=y_start
        self.x_end=x_end
        self.y_end=y_end

    @property
    def centroid(self):
        return (self.x_start+self.x_end)/2, (self.y_start+self.y_end)/2

    def __lt__(self, other):
        """Using "reading order" in a coordinate system where 0,0 is bottom left"""
        try:
            x0, y0 = self.centroid
            x1, y1 = other.centroid
            return (-y0, x0) < (-y1, x1)
        except AttributeError:
            return NotImplemented

    def __repr__(self):
        return 'Rectangle: ' + self.text

I'm defining centroid as a property, so that it will update if you change any of the other coordinates after initializing a Rectangle.

You will get this output if you use the data from your question.

>>> rectangles = [
...     Rectangle('A',1,3,2,4),
...     Rectangle('B',3,3,3,4),
...     Rectangle('C',1,1,2,2), 
... ]
>>> print(sorted(rectangles))
[Rectangle: A, Rectangle: B, Rectangle: C]

Upvotes: 3

Robᵩ
Robᵩ

Reputation: 168626

Generating a sorted list is the specialty of the builtin function sorted().

Sorting using multiple values can be accomplished by providing a key function, which key function returns the values as a tuple. The resulting list is then sorted according to the lexicographical ordering of the tuple.

#UNTESTED
my_sorted_list = sorted(my_list, key=lambda item: (item.x_centroid, item.y_centroid))

Upvotes: 4

Related Questions