Because this bit me harder than I was ready for, I thought I'd make a note of it for the next victim.

In Python 2, suppose you have this:

Python 2.7.5
>>> items = [(1, 'A number'), ('a', 'A letter'), (2, 'Another number')]

Sorting them, without specifying how, will automatically notice that it contains tuples:

Python 2.7.5
>>> sorted(items)
[(1, 'A number'), (2, 'Another number'), ('a', 'A letter')]

This doesn't work in Python 3 because comparing integers and strings is not allowed. E.g.:

Python 3.3.3
>>> 1 < '1'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()

You have to convert them to stings first.

Python 3.3.3
>>> sorted(items, key=lambda x: str(x[0]))
[(1, 'A number'), (2, 'Another number'), ('a', 'A letter')]

If you really need to sort by 1 < '1' this won't work. Then you need a more complex key function. E.g.:

Python 3.3.3
>>> def keyfunction(x):
...   v = x[0]
...   if isinstance(v, int): v = '0%d' % v
...   return v
...
>>> sorted(items, key=keyfunction)
[(1, 'A number'), (2, 'Another number'), ('1', 'Actually a string')]

That's really messy but the best I can come up with at past 4PM on Friday.

Joseph G. Mitzen - 18 January 2014 [«« Reply to this]
Nice solution! I guess you could make it even messier with a lambda:

sorted(items, key=lambda item: ('' if isinstance(item[0], int) else '0',)+item)
Steve Fink - 29 January 2014 [«« Reply to this]
Or use a tuple as a key:

  sorted(items, key=lambda x: (isinstance(x[0], str), x[0]))

but it seems like it'd be better to not have mixed types in the first place.
Philippe Ombredanne - 08 March 2014 [«« Reply to this]
This is one more reason why Python3 is not really Python


Your email will never ever be published