Nicolas Hung
Nicolas Hung

Reputation: 603

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

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?

Upvotes: 42

Views: 61372

Answers (3)

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 251096

you can use collections.defaultdict:

In [48]: from collections import defaultdict

In [49]: dic=[('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]

In [50]: d=defaultdict(list)

In [51]: for x,y in dic:
    d[y].append(x)
    d[y].sort()          #sort the list

now d is something like:

 defaultdict(<type 'list'>, {1: ['A', 'I', 'J'], 2: ['A'], 3: ['B']}

i.e. A new dict with 1,2,3... as keys and corresponding alphabets stored in lists as values.

Now you can iterate over the sorted(d.items) and get the desired result using itertools.chain() and itertools.product().

In [65]: l=[ product(y,[x]) for x,y in sorted(d.items(),reverse=True)]

In [66]: list(chain(*l))
Out[66]: [('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]

Upvotes: 2

mgilson
mgilson

Reputation: 310089

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.

Upvotes: 71

NPE
NPE

Reputation: 500733

In [4]: l = [('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]

In [5]: sorted(l, key=lambda (x,y):(-y,x))
Out[5]: [('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]

Upvotes: 5

Related Questions