1

Lets say you have a list of tuples (last_name, first_name) and you want to sort them reverse alphabetically by last_name and then if two people have the same name for them to be sorted alphabetically by first name. Is there a way to do this with one line?

e.g.

Sorted(names, key = ?) = [('Zane', 'Albert'), ('Zane', 'Bart'), ('Python', 'Alex'), ('Python', 'Monty')]

With two lines I guess you could rely on sort stability and first sort by first name and then sort by last name reversed.

Seraphya
  • 165
  • 1
  • 1
  • 8

3 Answers3

2

Is there a way to do this with one line?

With two lines I guess you could rely on sort stability and first sort by first name and then sort by last name reversed.

Well you can do exactly that in one line:

sorted(sorted(names, key=lambda name: name[1]), key=lambda name: name[0], reverse=True)

Doing two sorts for exactly this problem in the Sorting Mini-HOW TO ("to sort the student data by descending grade and then ascending age, do the age sort first and then sort again using grade").


A silly alternative doing it with just one sorted and key:

sorted(names, key=lambda name: ([-ord(c) for c in name[0]], name[1])) == correct

A Python 2 solution with one sorted and cmp instead of key:

sorted(names, lambda a, b: cmp(b[0], a[0]) or cmp(a, b))
Community
  • 1
  • 1
Stefan Pochmann
  • 27,593
  • 8
  • 44
  • 107
1

Here's an itertools.groupby solution:

from itertools import groupby
from operator import itemgetter

li = [('x', 'y'), ('s', 'e'), ('s', 'a'), ('x', 'z')]

[p for k, g in groupby(sorted(li, reverse=True), itemgetter(0)) for p in reversed(list(g))]
# [('x', 'y'), ('x', 'z'), ('s', 'a'), ('s', 'e')]
 
Augustin
  • 2,444
  • 23
  • 24
Paul Panzer
  • 51,835
  • 3
  • 54
  • 99
0

Yes, you can rely on the stability of the sorting:

names = [('Zane', 'Albert'), ('Zane', 'Bart'), ('Python', 'Alex'), ('Python', 'Monty')]

names.sort()
names.sort(reverse=True, key=lambda i: i[0])
Peter Gerber
  • 1,023
  • 10
  • 13