3

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.

Community
  • 1
  • 1
crazyminer
  • 59
  • 5

2 Answers2

3

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]
]
tmthydvnprt
  • 10,398
  • 8
  • 52
  • 72
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • nice work:) but why the cmp way failed to reach the right answer? any bugs in the code? – crazyminer Mar 28 '14 at 10:02
  • @crazyminer False == 0 in Python, so according to your code `[1,2,3]` and `[3, 2, 2]` are equal, and because Python's sort is stable sort `[1, 2, 3]` is returned first. – Ashwini Chaudhary Mar 28 '14 at 10:08
1

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.

Selcuk
  • 57,004
  • 12
  • 102
  • 110