8

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?

RocketDonkey
  • 36,383
  • 7
  • 80
  • 84
user1973325
  • 81
  • 1
  • 1
  • 2
  • You probably want to read the [Python Sorting HowTo](http://wiki.python.org/moin/HowTo/Sorting/). (Actually, I'm having trouble loading it at the moment, but there's always [Google Cache](http://webcache.googleusercontent.com/search?q=cache:GjjYVDIjFi0J:wiki.python.org/moin/HowTo/Sorting/+&cd=1&hl=en&ct=clnk&gl=us&client=firefox-a)) – kojiro Jan 13 '13 at 00:41
  • Wow. I have exactly same task: sort teams in league) – imkost Apr 15 '13 at 22:51
  • Possible duplicate of [Sorting a Python list by two criteria](http://stackoverflow.com/questions/5212870/sorting-a-python-list-by-two-criteria) – GingerPlusPlus Jan 13 '16 at 18:59

3 Answers3

15

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'))
millimoose
  • 39,073
  • 9
  • 82
  • 134
  • 1
    Isn't the first a little different from the second? It applies `reverse=True` to the whole tuple, whereas the three-step version only applies it to the points. – DSM Jan 13 '13 at 00:42
  • @DSM It is, I was trying to make an example that you *can* change the order for the various steps, but I guess it's not obvious and confusing. – millimoose Jan 13 '13 at 00:43
  • Well, couldn't you just use `*-1` to reverse a field? – Snakes and Coffee Jan 13 '13 at 00:45
  • @SnakesandCoffee What if it's a string? – millimoose Jan 13 '13 at 00:55
  • the function names seem to imply that they're numbers (except `getName`). – Snakes and Coffee Jan 13 '13 at 01:05
  • @SnakesandCoffee Which is my point exactly. There's a reason why `reverse=True` is there, which is that **in general** it may not be convenient to calculate the inverse of a sort key, while the sort algorithm can just do the opposite operation easily. (Unless you do something ugly with `cmp` and `cmp_to_key`.) – millimoose Jan 13 '13 at 02:38
4

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.

ACEfanatic02
  • 704
  • 5
  • 13
0

Python sorting algorithm is Timsort which, as ACEfanatic02 points out, is stable which means order is preserved. This link has a nice visual explanation of how it works.

Zenon
  • 1,481
  • 12
  • 21