cs95
cs95

Reputation: 402603

Sort a list of strings based on multiple predicates

Given a list a strings:

['foo2', 'abacus', 'azz', 'foo', 'foo3', 'bar', 'azb', 'bars13']

This is how the normal sorted version looks like after calling sorted:

['abacus', 'azb', 'azz', 'bar', 'bars13', 'foo', 'foo2', 'foo3']

I want to first order them all, and then, for all strings with the same first letter, sort in descending order.

For the example above, I want

['azz', 'azb', 'abacus', 'bars13', 'bar', 'foo3', 'foo2', 'foo']

How can I do this?

Upvotes: 1

Views: 260

Answers (2)

Massimiliano
Massimiliano

Reputation: 8032

A two pass solution that goes on the same line as @COLDSPEED:

>>> import itertools
>>>
>>> l = ['foo2', 'abacus', 'azz', 'foo', 'foo3', 'bar', 'azb', 'bars13']
>>> s = sorted(l, key=lambda x:(x, len(x)))
>>> t = []
>>>
>>> for g, elems in itertools.groupby(s, key=lambda x: x[0]):
...     t.extend(reversed(list(elems)))
>>>
>>> t
['azz', 'azb', 'abacus', 'bars13', 'bar', 'foo3', 'foo2', 'foo']

Upvotes: 0

augurar
augurar

Reputation: 13026

You could first sort in descending order, then sort by first letter. Since Python's sorting algorithm is stable, this will result in all "ties" in the second sort (i.e. words with the same first letter) remaining in the same relative order as the first sort.

l = sorted(l, reverse=True)
l = sorted(l, key=lambda s: s[0])

You could also do this in one call to sorted() as follows:

l = sorted(l, key=lambda s: (-ord(s[0]), s), reverse=True)

Upvotes: 1

Related Questions