Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why multilevel sort using sorted function in python get the wrong answer?

This post is not the same as How do I sort a list of dictionaries by values of the dictionary in Python?, which I think can not be solved using lambda sort, since the sort should be done on two properties, one ascending and the other descending.

I think it's answer should be

descending on column 2 and ascending on column 3

[1, 5, 7]
[2, 3, 4]
[3, 2, 2]
[1, 2, 3]
[4, 2, 9]
[3, 1, 9]

but the output is:

[1, 5, 7]
[2, 3, 4]
[1, 2, 3]
**[3, 2, 2]**   i think it's wrong here
[4, 2, 9]
[3, 1, 9]

The code is as follows

l=[
        [1,2,3],
        [2,3,4],
        [1,5,7],
        [3,1,9],
        [3,2,2],
        [4,2,9]
   ]

def printlist(l):
    for ll in l:
        print ll

def comp1(a,b):
    if a[1]<b[1]:
        return 1
    if a[1]==b[1]:
        return a[2]>b[2]
    else:
        return -1

l3=sorted(l,cmp=comp1)
printlist(l3)

So why the program output the wrong answer?

Edit1: Here I choose cmp rather than key=itemgetter(2,3) since there could be more complex structures, which can not be sorted using itemgetter, but can only be sorted using the cmp function.

like image 840
crazyminer Avatar asked Feb 12 '26 01:02

crazyminer


2 Answers

This should do it:

>>> sorted(l, key= lambda x:(-x[1], x[2]))
[
    [1, 5, 7], 
    [2, 3, 4], 
    [3, 2, 2], 
    [1, 2, 3], 
    [4, 2, 9], 
    [3, 1, 9]
]
like image 189
Ashwini Chaudhary Avatar answered Feb 14 '26 14:02

Ashwini Chaudhary


Your comp1 function should return a positive or negative integer:

http://docs.python.org/2.7/library/functions.html#sorted

cmp specifies a custom comparison function of two arguments (iterable elements) which should return a negative, zero or positive number depending on whether the first argument is considered smaller than, equal to, or larger than the second argument: cmp=lambda x,y: cmp(x.lower(), y.lower()). The default value is None.

In the following line you are returning a boolean value:

return a[2]>b[2]

According to the official documentation:

Boolean values are the two constant objects False and True. They are used to represent truth values (although other values can also be considered false or true). In numeric contexts (for example when used as the argument to an arithmetic operator), they behave like the integers 0 and 1, respectively.

Therefore False returns 0 instead of -1. Replace it with

return a[2] - b[2]

and you are good to go.

like image 45
Selcuk Avatar answered Feb 14 '26 15:02

Selcuk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!