Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python sorted function with user defined cmp functions

Tags:

python

sorted

I want to order the items in a dictionary using various comparator functions. Please see my example code below. It is the last part using cmpRatio function with sorted() that does not work. I am not sure what I am doing wrong. Thanks in advance for any idea!

mydict = { 'a1': (1,6),
          'a2': (10,2),
          'a3': (5,3),
          'a4': (1,2),
          'a5': (3,9),
          'a6': (9,7) }

# sort by first element of the value tuple: WORKS
print sorted(mydict.iteritems(), key=lambda (k,v): v[0])

# sort by second element of the value tuple: WORKS
print sorted(mydict.iteritems(), key=lambda (k,v): v[1])

# THIS is what I can't get working:
def cmpRatio(x,y):
   sx = float(x[0])/x[1]
   sy = float(y[0])/y[1]
   return sx < sy

# sort by sum of the elements in the value tuple: DOES NOT WORK
print sorted(mydict.iteritems(), key=lambda (k,v): v, cmp=cmpRatio)
like image 829
Ruxandra Palmtag Avatar asked Nov 21 '12 19:11

Ruxandra Palmtag


People also ask

What is CMP in sort Python?

The cmp Argument In Python 2, . sort() or sorted() functions have a cmp parameter, which determines the sort order. The argument for cmp is a function that, like all cmp-style functions, returns a negative, zero, or positive result depending on the order of its two arguments.

How do you sort a list with custom functions in Python?

In Python, we can write custom sort functions that work with sort() and sorted() . The value of the key parameter should be a function that takes a single argument and returns a key for sorting purposes.

What is the difference between sort () and sorted () in Python?

The main difference between sort and sorted in Python is that sort function returns nothing and makes changes to the original sequence, while the sorted () function creates a new sequence type containing a sorted version of the given sequence.

How sorted () can be used with list in Python?

The sorted() function returns a sorted list of the specified iterable object. You can specify ascending or descending order. Strings are sorted alphabetically, and numbers are sorted numerically. Note: You cannot sort a list that contains BOTH string values AND numeric values.


2 Answers

Avoid cmp functions where possible because they are slow. They have to be re-evaluated for each comparison. Using a key makes it so the key only needs to be computed once.

print sorted(mydict.iteritems(), key=lambda (k,v): float(v[0])/v[1])

Also, you say you want to sort by the sum of the value items, yet you are sorting by the difference. Sum would look like:

print sorted(mydict.iteritems(), key=lambda (k,v): sum(v))

As mentioned in other answers, for the purpose of really wanting to define a cmp function, you are not returning the proper value (must be -1,0, or 1).

return cmp(sx,sy)

But also if you are just using a lambda to get the value, you can replace that with itemgetter which should be faster than a python-side function:

from operator import itemgetter

print sorted(mydict.iteritems(), key=itemgetter(1), cmp=cmpRatio)

If you are trying to store up sort operations, it would be much better to store the key functions:

key_ops = {
    'sum': lambda (k,v): sum(v),
    'ratio': lambda (k,v): float(v[0])/v[1]),
}

def print_op(aDict, opName):
    print sorted(aDict.iteritems(), key=key_ops[opName])

... # some place later in code
print_op(mydict, 'sum')
like image 106
jdi Avatar answered Oct 19 '22 22:10

jdi


you comparison function should return a (negative / zero / positive) value when the first argument is (less than / equal to / greater than) the second value (unlike a comparator given to std::sort(...) in C++).

i.e. instead of

return sx < sy

do

return cmp(sx,sy)
like image 25
Andre Holzner Avatar answered Oct 19 '22 22:10

Andre Holzner