Juan Huerta
Juan Huerta

Reputation: 65

Order dictionary with x and y coordinates in python

I have this problem.

I need order this points 1-7 1(4,2), 2(3, 5), 3(1,4), 4(1,1), 5(2,2), 6(1,3), 7(1,5)

and get this result 4 , 6 , 3 , 5 , 2 , 1 , 7.

enter image description here

I am using a python script for sort with x reference and is ok, but the sort in y is wrong.

I have tried with sorted(dicts,key=itemgetter(1,2))

Someone can help me please ?

Upvotes: 0

Views: 4489

Answers (3)

RightmireM
RightmireM

Reputation: 2492

Since you're searching visually from top-to-bottom, then left-to-right, this code is much simpler and provides the correct result. It basically does the equivalent of a visual scan, by checking for all tuples that are at each "y=n" position, and then sorting any "y=n" tuples based on the second number (left-to-right).

Just to be more consistent with the Cartesian number system, I've converted the points on the graph to (x,y) coordinates, with X-positive (increasing to the right) and y-negative (decreasing as they go down).

d = {(2,-4):1, (5,-3):2, (4,-1):3, (1,-1):4, (2,-2):5, (3,-1):6, (1,-5):7}
l = [(2,-4), (5,-3), (4,-1), (1,-1), (2,-2), (3,-1), (1,-5)]

results = []
# Use the length of the list. Its more than needed, but guarantees enough loops
for y in range(0, -len(l), -1):
    # For ONLY the items found at the specified y coordinate 
    temp_list = []
    for i in l: # Loop through ALL the items in the list
        if i[1] == y: # If tuple is at this "y" coordinate then...
            temp_list.append(i) # ... append it to the temp list
    # Now sort the list based on the "x" position of the coordinate
    temp_list = sorted(temp_list, key=lambda x: x[0])
    results += temp_list # And just append it to the final result list
# Final TUPLES in order
print(results)
# If you need them correlated to their original numbers
by_designator_num = []
for i in results: # The the first tupele value
    by_designator_num.append(d[i]) # Use the tuple value as the key, to get the original designator number from the original "d" dictionary
print(by_designator_num)

OR if you want it faster and more compact

d = {(2,-4):1, (5,-3):2, (4,-1):3, (1,-1):4, (2,-2):5, (3,-1):6, (1,-5):7}
l = [(2,-4), (5,-3), (4,-1), (1,-1), (2,-2), (3,-1), (1,-5)]

results = []
for y in range(0, -len(l), -1):
    results += sorted([i for i in l if i[1] == y ], key=lambda x: x[0])
print(results)

by_designator_num = [d[i] for i in results]
print(by_designator_num)

OUTPUT:

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

Upvotes: 0

RightmireM
RightmireM

Reputation: 2492

This sorts the code based on ordering the first coordinate of the tuple, and then sub-ordering by the second coordinate of the tuple. I.e. Like alphabetically where "Aa", then "Ab", then "Ba", then "Bb". More literall (1,1), (1,2), (2,1), (2,2), etc.

This will work IF (and only if) the tuple value pair associated with #7 is actually out of order in your question (and should actually be between #3 and #5.)

If this is NOT the case, See my other answer.

# Make it a dictionary, with the VALUETUPLES  as the KEYS, and the designator as the value
d = {(1,1):4, (1,3):6, (1,4):3, (2,2):5, (3,5):2, (4,2):1,(1,5):7}
# ALSO make a list of just the value tuples
l = [ (1,1), (1,3), (1,4), (2,2), (3,5), (4,2), (1,5)]

# Sort the list by the first element in each tuple. ignoring the second
new = sorted(l, key=lambda x: x[0])

# Create a new dictionary, basically for temp sorting
new_d = {}
# This iterates through the first sorted list "new"
# and creates a dictionary where the key is the first number of value tuples
count = 0
# The extended range is because we don't know if any of the Tuple Values share any same numbers
for r in range(0, len(new)+1,1): 
    count += 1
    new_d[r] = []
    for item in new:
        if item[0] == r:
            new_d[r].append(item)

print(new_d) # So it makes sense

# Make a final list to capture the rdered TUPLES VALUES
final_list = []
# Go through the same rage as above
for r in range(0, len(new)+1,1):
    _list = new_d[r] # Grab the first list item from the dic. Order does not matter here
    if len(_list) > 0: # If the list has any values...
        # Sort that list now by the SECOND tuple value
        _list = sorted(_list, key=lambda x: x[1])
        # Lists are ordered. So we can now just tack that ordered list onto the final list. 
        # The order remains
        for item in _list: 
            final_list.append(item)

# This is all the tuple values in order
print(final_list)
# If you need them correlated to their original numbers
by_designator_num = []
for i in final_list: # The the first tupele value
    by_designator_num.append(d[i]) # Use the tuple value as the key, to get the original designator number from the original "d" dictionary

print(by_designator_num)

OUTPUT:

[(1, 1), (1, 3), (1, 4), (1, 5), (2, 2), (3, 5), (4, 2)]
[4, 6, 3, 7, 5, 2, 1]              

Upvotes: 0

Huw Thomas
Huw Thomas

Reputation: 317

Try this:

sorted(dicts,key=itemgetter(1,0))

Indexing in python starts at 0. itemgetter(1,0) is sorting by the second element and then by the first element

Upvotes: 2

Related Questions