LaneL
LaneL

Reputation: 778

How to sort a collection based on another collection in Python?

I'm very new to Python and I need help with the following problem. This definition that I have posted below will take in a collection of tuples that represent rectangles Ex. (width,height).

In the method, I first sort the rectangle collection so that the elements with the largest width are at the beginning of the list, I then use this collection later to assign UPPER_LEFT_X and UPPER_LEFT_Y coordinates for each rectangle.

My question is, how do I take this collection of coordinates and sort it in a way that it is in the exact same order as the original_rectangle_collection? The way that the Driver works, is that the determined coordinates have to be given in the same order as the original rectangle collection. Thanks! Let me know if more explanation is required.

def find_best_coordinates(rectangles):
    placement = []
    upper_left_x = 0
    upper_left_y = 0
    loop_count = 0

    original_rectangle_collection = rectangles
    #sort the rectangles according to width.
    rectangles.sort(key=operator.itemgetter(0))
    #reverse the list so the tallest rectanlgle is placed first
    rectangles.reverse()


    #set the max width to the tallest rectangle's width
    max_width = rectangles[0][0]
    #print("Max width",max_width)

    #loop through and place the rectangles
    for rectangle in rectangles:
        if loop_count == 0:
            max_width = rectangle[0]
        height = rectangle[1]
        coordinate = (upper_left_x, upper_left_y)  
        placement.insert(0, coordinate)             
        upper_left_y = upper_left_y - height - 990
        loop_count = loop_count + 1
        if loop_count == 50:
            upper_left_x = upper_left_x + max_width + 990
           # print("x = ", upper_left_x)
            loop_count = 0
            #print("y = ", upper_left_y)
            upper_left_y = 0

    #reverse the list before it gets returned
    placement.reverse()                            
    return placement

Upvotes: 2

Views: 289

Answers (2)

aghast
aghast

Reputation: 15310

You can go a little faster by just sorting the indexes:

processing_order = sorted(
    range(len(rectangles)), 
    key=lambda i: rectangles[i][0]
)

for rect_i in processing_order:
    r = rectangles[rect_i]
    # ... blah blah with r as current rectangle

# Done processing, output them in original order:
for r in rectangles:
    # Still in order!

Upvotes: 1

Brendan Abel
Brendan Abel

Reputation: 37539

You could do it this way, by always passing the original index along with the rectangle, and keeping it with the generated coordinate.

# Store indexes
rdicts = [{'index': i, 'rectangle': r} for i, r in enumerate(rectangles)]
# Sort by width
rdicts.sort(key=lambda d: d['rectangle'][0], reverse=True)

placement = []
for rdict in rdicts:
    rectangle = rdict['rectangle']
    ... # do the rest of your algorithm
    # Add the calculated coordinate, along with the original index
    placement.append({'index': rdict['index'], 'coordinate': coordinate})

# Sort by the original index
placement.sort(key=lambda p: p['index'])
# Return the coordinates without the indexes.
ordered_placement = [p['coordinate'] for p in placement]

Upvotes: 2

Related Questions