Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting by multiple conditions in python

Tags:

python

sorting

I am new to programming and right now i'm writing a league table in python. I would like to sort my league by first points, and if there are two teams with the same points I would like to sort them by goal difference, and if they have the same goal difference i would like to sort by name.

The first condition is pretty easy and is working by the following:

table.sort(reverse=True, key=Team.getPoints)

how do I insert the two following conditions?

like image 358
user1973325 Avatar asked Jan 13 '13 00:01

user1973325


2 Answers

Have the key function return a tuple, with items in decreasing order of priority:

table.sort(reverse=True, key=lambda team: (Team.getPoints(team),
                                           Team.getGoalDifference(team),
                                           Team.getName(team))

Alternately, you could remember a factoid from algorithms 101, and make use of the fact .sort() is a stable sort, and thus doesn't change the relative order of items in a list if they compare as equal. This means you can sort three times, in increasing order of priority:

table.sort(reverse=True, key=Team.getName)
table.sort(reverse=True, key=Team.getGoalDifference)
table.sort(reverse=True, key=Team.getPoints)

This will be slower, but allows you to easily specify whether each step should be done in reverse or not. This can be done without multiple sorting passes using cmp_to_key(), but the comparator function would be nontrivial, something like:

def team_cmp(t1, t2):
    for key_func, reverse in [(Team.getName, True),
                              (Team.getGoalDifference, True),
                              (Team.getPoints, True)]:
        result = cmp(key_func(t1), key_func(t2))
        if reverse: result = -result;
        if result: return result
    return 0

table.sort(functools.cmp_to_key(team_cmp))

(Disclaimer: the above is written from memory, untested.) Emphasis is on "without multiple passes", which does not necessarily imply "faster". The overhead from the comparator function and cmp_to_key(), both of which are implemented in Python (as opposed to list.sort() and operator.itemgetter(), which should be part of the C core) is likely to be significant.

As an aside, you don't need to create dummy functions to pass to the key parameters. You can access the attribute directly, using:

table.sort(key=lambda t: t.points)

or the attrgetter operator wrapper:

table.sort(key=attrgetter('points'))
like image 189
millimoose Avatar answered Sep 21 '22 15:09

millimoose


Sort the list by name first, then sort again by score difference. Python's sort is stable, meaning it will preserve order of elements that compare equal.

like image 22
ACEfanatic02 Avatar answered Sep 20 '22 15:09

ACEfanatic02