Sorting mixed type lists in Python 3

18 January 2014   4 comments   Python

Powered by Fusion×

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.

Comments

Joseph G. Mitzen
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
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
This is one more reason why Python3 is not really Python
Nicolas
What about integer to tuple comparison?
Python 2 could sort the following, while Python 3 could not. Any suggestions are appreciated.

(1, (11, 8, 7, 6, 2)) # high card 11 (rank5)
(1, (12, 11, 8, 7, 2)) # high card 12 (rank4)
((3, 2), (11, 12)) # full house (triple and pair) (rank1)
((2, 1, 1, 1), (12, 11, 7, 6)) # pair of 12 (rank3)
((3, 1, 1), (12, 6, 3)) # three of 12 (rank2)
Thank you for posting a comment

Your email will never ever be published


Related posts

Previous:
How I do deployments 16 December 2013
Next:
Advanced live-search with AngularJS 04 February 2014
Related:
Premailer on Python 3 08 October 2014
In Python you sort with a tuple 14 June 2013
Calculator in Python for dummies 17 December 2007
Find largest directories with du -k 29 December 2006
Unicode strings to ASCII ...nicely 08 August 2006
Interesting float/int casting in Python 25 April 2006