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)
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.
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.
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.
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.
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')
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With