69

Empirically, it seems that Python's default list sorter, when passed a list of tuples, will sort by the first element in each tuple. Is that correct? If not, what's the right way to sort a list of tuples by their first elements?

mike
  • 46,876
  • 44
  • 102
  • 112

5 Answers5

84

It automatically sorts a list of tuples by the first elements in the tuples, then by the second elements and so on tuple([1,2,3]) will go before tuple([1,2,4]). If you want to override this behaviour pass a callable as the second argument to the sort method. This callable should return 1, -1, 0.

Vasil
  • 36,468
  • 26
  • 90
  • 114
  • 17
    Don't use the cmp argument if the key argument to sort will do though! That is prefer foo.sort(key=lambda x: x[1]) to foo.sort(lambda x, y: cmp(x[1], y[1])). It's both easier to understand and much more efficient. – cthulahoops Mar 14 '09 at 00:20
  • 10
    @cthulahoops I think that using `operator.itemgetter` is in that case better than lambda function : `foo.sort(key=operator.itemgetter(1))` is nicer than `foo.sort(key=lambda x: x[1])`. It's just my opinion though. – Jarek Przygódzki Oct 25 '11 at 07:28
  • 2
    It would be nice to have a relevant link to the documentation though. –  Mar 29 '17 at 05:45
9

Yes, this is the default. In fact, this is the basis of the classic "DSU" (Decorate-Sort-Undecorate) idiom in Python. See Code Like a Pythonista.

zweiterlinde
  • 14,557
  • 2
  • 27
  • 32
  • 1
    10 years later the link is dead. Is [this](https://samyzaf.com/braude/PYTHON/tutorials/Python_coding_style.pdf) the article? Page 25 – alex Jan 20 '20 at 15:36
8

No, tuples are sequence types just like strings. They are sorted the same, by comparing each element in turn:

>>> import random
>>> sorted([(0,0,0,int(random.getrandbits(4))) for x in xrange(10)])
[(0, 0, 0, 0), (0, 0, 0, 4), (0, 0, 0, 5), (0, 0, 0, 7), (0, 0, 0, 8),
(0, 0, 0, 9), (0, 0, 0, 12), (0, 0, 0, 12), (0, 0, 0, 12), (0, 0, 0, 14)]

The three zeroes are only there to show that something other than the first element must be getting inspected.

unwind
  • 391,730
  • 64
  • 469
  • 606
0

Try using the internal list sort method and pass a lambda. If your tuples first element is a integer, this should work.

# l is the list of tuples
l.sort(lambda x,y: x-y)

You can use any callable for the compare function, not necessarily a lambda. However it needs to return -1 (less than), 0 (equal) or 1 (greater than).

m-sharp
  • 16,443
  • 1
  • 26
  • 26
  • -1: How will this work with a list of tuples? I get TypeError: unsupported operand type(s) for -: 'tuple' and 'tuple' – S.Lott Mar 13 '09 at 19:59
  • The lambda function that will be executed in sort has to have one argument, which is the iteratables element of a tupla serie: pairs.sort(key=lambda pair: pair[1]). pairs.sort(key=lambda pair: pair[1]) or pairs.sort(key=lambda pair: pair[1], pair[0]) if you want to have a second layer of order after ordering by the first element. – Alex Aug 20 '14 at 00:54
0

Check out "Devin Jeanpierre" answer to this question sort-a-dictionary-in-python-by-the-value where he says to use a tuple and shows how to sort by the second value

Community
  • 1
  • 1
Gern Blanston
  • 42,482
  • 19
  • 50
  • 64