Sorting mixed type lists in Python 3

18 January 2014   4 comments   Python

Mind That Age!

This blog post is 4 years old! Most likely, its content is outdated. Especially if it's technical.

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)

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 by Keyword:
Cope with JSONDecodeError in requests.get().json() in Python 2 and 3 16 November 2016
Premailer on Python 3 08 October 2014
In Python you sort with a tuple 14 June 2013
String length truncation optimization difference in Python 19 March 2012
Calculator in Python for dummies 17 December 2007
Related by Text:
jQuery and Highslide JS 08 January 2008
I'm back! Peterbe.com has been renewed 05 June 2005
Anti-McCain propaganda videos 12 August 2008
Ever wondered how much $87 Billion is? 04 November 2003
Guake, not Yakuake or Yeahconsole 23 January 2010