7

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

timgeb
  • 76,762
  • 20
  • 123
  • 145
user119o
  • 387
  • 2
  • 7
  • 14
  • 1
    What are the definitions of less than, equal to, and greater than for x and y? Specifically, which is less, (1, 2, 3) or (2, 1, 3), or are they considered equal for sorting? Or should you convert x and y to polar coordinates and use the length for sorting? –  Apr 13 '17 at 17:40
  • `correctC` is a bad name for the lambda argument, since you're reusing the same variable name for the list and its elements. – user2357112 Apr 13 '17 at 17:42
  • 1
    You should add the expected output to your question. –  Apr 13 '17 at 20:36
  • Does this answer your question? [Sort a list by multiple attributes?](https://stackoverflow.com/questions/4233476/sort-a-list-by-multiple-attributes) – user202729 Aug 14 '21 at 13:22

6 Answers6

7

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]))
eguaio
  • 3,754
  • 1
  • 24
  • 38
4

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)]
trust512
  • 2,188
  • 1
  • 18
  • 18
  • 3
    Cleaner way to write the lambda, since OP is using Python 2: `key= lambda (x, y, z): (x, y)`. Or `lambda tup: tup[:2]` for Python 3. – timgeb Apr 13 '17 at 17:28
  • 1
    @timgeb Isn't this the default sort order for tuples anyway? (Other than you are ignoring the third element.) – Code-Apprentice Apr 13 '17 at 17:37
  • 2
    `correctC` is a bad name for the lambda argument, since you're reusing the same variable name for the list and its elements. (I see that that name choice came from the question itself, though.) – user2357112 Apr 13 '17 at 17:41
  • @trust512 Thanks for the answer.... But look, 18 and 19 / 34 and 35 elements...that elements are not sorted correctly. 18 = (384, 236, 25) 19 = (386, 172, 22) Above 2 tuples are not correctly sorted according to y value and 34 and 35 34 = (732, 234, 22) 35 = (734, 172, 25) I also can see it from my last result like this, https://drive.google.com/file/d/0B53F0wBGnYhddktMV1ZTQlhGZHc/view?usp=sharing – user119o Apr 13 '17 at 17:54
  • 2
    @user119o: "Above 2 tuples are not correctly sorted according to y value" - yeah, because they're sorted by x value. The circles in your picture aren't arranged in perfect columns. If you want to detect the approximate grid structure and order the circles by that structure, you'll need something a lot more complex than a sort by two keys. – user2357112 Apr 13 '17 at 18:46
  • @user2357112 Yes.. I understood. Actually I need like this output. https://drive.google.com/file/d/0B53F0wBGnYhdWkRiN1pNVXNXYlE/view?usp=sharing I make simple sorting 2 times for that. First I sort it according to x value and result is broken in to parts (for get the columns) then I sort it according to y value for each one and at last I join all. Thanks all. – user119o Apr 13 '17 at 18:47
  • @Code-Apprentice that's right. Explicitly ignoring the third element is probably pointless. – timgeb Apr 13 '17 at 19:16
4

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).

Community
  • 1
  • 1
2

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.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
2

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)))
  • Thanks...I got lot of ideas from your answer. Actually I got the idea about what i want to do after your answer. Actually it's not about sort by distance... you can see what I wanted in this picture: https://drive.google.com/file/d/0B53F0wBGnYhdWkRiN1pNVXNXYlE/view?usp=sharing – user119o Apr 13 '17 at 18:40
0

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)
Ruman
  • 936
  • 11
  • 9