Sort Python list using multiple keys

Question:

I have searched lot of time for this. I have got some idea about sorting using key parameter.

I have a list of tuple like this. It’s got by OpenCV Hough Circle detection.

correctC = [(298, 172, 25), (210, 172, 25), (470, 172, 25), (386, 172, 22), (648, 172, 25), (384, 44, 22), (558, 110, 22), (562, 170, 25), (382, 108, 25), (734, 172, 25), (126, 172, 24), (646, 44, 22), (296, 110, 23), (126, 234, 26), (470, 236, 25), (296, 44, 25), (208, 108, 24), (38, 170, 25), (730, 110, 22), (730, 44, 25), (468, 110, 23), (468, 44, 25), (208, 44, 25), (124, 44, 22), (558, 44, 22), (36, 110, 24), (36, 44, 22), (298, 234, 26), (210, 236, 25), (648, 234, 25), (732, 234, 22), (562, 234, 26), (384, 236, 25), (38, 234, 26), (646, 110, 25), (124, 112, 27)]

It has 3 values. center coordinate(x,y) and radius.

I need to sort all tuples using it’s x and y value.

I can do this sorting separately.

xS=sorted(correctC,key=lambda correctC: correctC[0])

This is sort according to x value only.

yS=sorted(correctC,key=lambda correctC: correctC[1])

This is sort according to y value only.

How can I do both(according to x value and y value) using one expression?

I’m using Python 2.7

Asked By: user119o

||

Answers:

From what I can see, this helps:

sorted(correctC, key=lambda correctC:[correctC[0],correctC[1]])

Sorted result:

[(36, 44, 22), (36, 110, 24), (38, 170, 25), (38, 234, 26), (124, 44, 22), (124, 112, 27), (126, 172, 24), (126, 234, 26), (208, 44, 25), (208, 108, 24), (210, 172, 25), (210, 236, 25), (296, 44, 25), (296, 110, 23), (298, 172, 25), (298, 234, 26), (382, 108, 25), (384, 44, 22), (384, 236, 25), (386, 172, 22), (468, 44, 25), (468, 110, 23), (470, 172, 25), (470, 236, 25), (558, 44, 22), (558, 110, 22), (562, 170, 25), (562, 234, 26), (646, 44, 22), (646, 110, 25), (648, 172, 25), (648, 234, 25), (730, 44, 25), (730, 110, 22), (732, 234, 22), (734, 172, 25)]
Answered By: trust512

Why do you need to provide a key at all? Tuples are sorted lexicographically (“dictionary order”)by default. The first elements will be compared. If they are the same, then the second elements of each tuple will be compared, and so on. meaning that the first element is compared and if they are the same, then go to the next element (basically “dictionary ordering”). If you rely on this, you will get exactly what you want, other than if two circles have the same center, then they will also be sorted by radius.

Answered By: Code-Apprentice

In this particular case, if you don’t care about how the points with equal x, y value are arranged, just calling sort will do the job. Tuples are sorted in lexicographic order.

correctC.sort()

If you want to be more explicit, just do as the other answer tells:

correctC.sort(key=lambda t: (t[0], t[1]))
Answered By: eguaio

Assuming that you want to sort by distance from the origin, this is what you want:

import math

sortedC = sorted(correctC, 
                 cmp=lambda lhs, rhs: cmp(math.sqrt(lhs[0] ** 2 + lhs[1] ** 2),
                                          math.sqrt(rhs[0] ** 2 + rhs[1] ** 2)))
Answered By: David Cullen

For anyone confused by the combination of

  • Unclear question
  • Accepted answer
  • OP user119o‘s comments

It looks like the OP wanted something like this:

sortedC = sorted(correctC)
for index in range(0, len(sortedC), 4):
    sortedC[index:index + 4] = sorted(sortedC[index:index + 4], key=lambda x: x[1])

The second column of tuples shows the expected output (which should have been included in the question):

 0  ( 36,  44,  22)  ( 36,  44,  22)  
 1  ( 36, 110,  24)  ( 36, 110,  24)  
 2  ( 38, 170,  25)  ( 38, 170,  25)  
 3  ( 38, 234,  26)  ( 38, 234,  26)  
 4  (124,  44,  22)  (124,  44,  22)  
 5  (124, 112,  27)  (124, 112,  27)  
 6  (126, 172,  24)  (126, 172,  24)  
 7  (126, 234,  26)  (126, 234,  26)  
 8  (208,  44,  25)  (208,  44,  25)  
 9  (208, 108,  24)  (208, 108,  24)  
10  (210, 172,  25)  (210, 172,  25)  
11  (210, 236,  25)  (210, 236,  25)  
12  (296,  44,  25)  (296,  44,  25)  
13  (296, 110,  23)  (296, 110,  23)  
14  (298, 172,  25)  (298, 172,  25)  
15  (298, 234,  26)  (298, 234,  26)  
16  (382, 108,  25)  (384,  44,  22)  True
17  (384,  44,  22)  (382, 108,  25)  True
18  (384, 236,  25)  (386, 172,  22)  True
19  (386, 172,  22)  (384, 236,  25)  True
20  (468,  44,  25)  (468,  44,  25)  
21  (468, 110,  23)  (468, 110,  23)  
22  (470, 172,  25)  (470, 172,  25)  
23  (470, 236,  25)  (470, 236,  25)  
24  (558,  44,  22)  (558,  44,  22)  
25  (558, 110,  22)  (558, 110,  22)  
26  (562, 170,  25)  (562, 170,  25)  
27  (562, 234,  26)  (562, 234,  26)  
28  (646,  44,  22)  (646,  44,  22)  
29  (646, 110,  25)  (646, 110,  25)  
30  (648, 172,  25)  (648, 172,  25)  
31  (648, 234,  25)  (648, 234,  25)  
32  (730,  44,  25)  (730,  44,  25)  
33  (730, 110,  22)  (730, 110,  22)  
34  (732, 234,  22)  (734, 172,  25)  True
35  (734, 172,  25)  (732, 234,  22)  True

Where there is a True in the fourth column, the expected output differs from sorted(correctC).

Answered By: David Cullen

You can solve this problem writing a lambda function for you or using built-in itemgetter() offered by python

Solution – 01:

sorted_correctC = sorted(correctC, key = lambda x : x[0:2])
print(sorted_correctC)

Solution – 02

from operator import itemgetter

sorted_correctC2 = sorted(correctC, key = itemgetter(0,1))
print(sorted_correctC2)
Answered By: Ruman
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.