Sort a list of tuples by second value, reverse=True and then by key, reverse=False

Nicolas Hung picture Nicolas Hung · Jan 22, 2013 · Viewed 43.4k times · Source

I need to sort a dictionary by first, values with reverse=True, and for repeating values, sort by keys, reverse=False

So far, I have this

dict = [('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]
sorted(dict.items(), key=lambda x: (x[1],x[1]), reverse=True)

which returns...

[('B', 3), ('A', 2), ('J', 1), ('I', 1), ('A', 1)]

but I need it to be:

[('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]

as you can see, when values are equal, I can only sort the key in a decreasing fashion as specified... But how can I get them to sort in an increasing fashion?

Answer

mgilson picture mgilson · Jan 22, 2013

The following works with your input:

d = [('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]
sorted(d,key=lambda x:(-x[1],x[0]))

Since your "values" are numeric, you can easily reverse the sort order by changing the sign.

In other words, this sort puts things in order by value (-x[1]) (the negative sign puts big numbers first) and then for numbers which are the same, it orders according to key (x[0]).

If your values can't so easily be "negated" to put big items first, an easy work-around is to sort twice:

from operator import itemgetter
d.sort(key=itemgetter(0))
d.sort(key=itemgetter(1),reverse=True)

which works because python's sorting is stable.