3

I have a list d that I wish to sort. I sort by the first column first. If its a tie there I then go on to use the second column to sort. Say I want to sort by the first column in ascending order but sort by the second column in descending order. Ascending being the default, using the reverse key I thought the below should work.

sorted(d,key=lambda x: (x[0],x[1]),reverse=(False,True))

But it does not. It give the following error.

    reverse=(False,True))

TypeError: an integer is required (got type tuple)

So if I'm not doing it right how to fix it? Or the way to do this is completely different? Advice on that would be helpful.

My question indeed has some duplication but there are already interesting responses, so I would like to keep it.

Ronan Boiteau
  • 9,608
  • 6
  • 34
  • 56
ztyh
  • 401
  • 5
  • 11
  • Are the values numeric? If so, you can use negation to reverse the sort order for the second element: `sorted(d,key=lambda x: (x[0],-x[1]))`. It would be helpful if you shared a sample of your list `d`. – pault Jul 09 '18 at 19:23
  • @pault good point. Some coloumns can indeed be strings. – ztyh Jul 09 '18 at 19:45

3 Answers3

7

(Might be overkill, but..) Using pandas and args ascending=[True, False]:

d = [[1,2], [2,2], [2,3], [2,4], [3,1]]
df=  pd.DataFrame(d)

sorted_values = df.sort_values(by=[0,1], ascending=[True,False])
sorted_list = sorted_values.agg(list,1).tolist()

[[1, 2], [2, 4], [2, 3], [2, 2], [3, 1]]
rafaelc
  • 57,686
  • 15
  • 58
  • 82
  • 1
    This is worth adding to the canonical question, which I believe is [this one](https://stackoverflow.com/questions/11206884/how-to-write-python-sort-key-functions-for-descending-values). – pault Jul 09 '18 at 19:39
  • 1
    I have followed your suggestion @pault thank you :) – rafaelc Jul 09 '18 at 20:08
1

From the docs:

reverse is a boolean value. If set to True, then the list elements are sorted as if each comparison were reversed.

So what you want instead is something like:

d.sort(key=lambda x: (x[0], -x[1]))

If x[1] is not a number, try:

d.sort(key=lambda x: x[1], reverse=True)
d.sort(key=lambda x: x[0])
minmax
  • 493
  • 3
  • 10
1

My take on solution:

from itertools import groupby, chain

l = ((1, 'b'),
     (1, 'd'),
     (2, 'a'),
     (1, 'a'))

def sort_multi(lst, index_normal, index_reversed):
    return list(chain.from_iterable([sorted(list(j), key=lambda v:v[index_reversed], reverse=True) for i, j in groupby(sorted(lst), key=lambda v:v[index_normal])]))


print(sort_multi(l, 0, 1))

Outputs:

[(1, 'd'), (1, 'b'), (1, 'a'), (2, 'a')]
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91