Python tip: Sorting lists by its contents

Not sure why this was so hard for me to use the sorted() method this morning.

I’m playing with the FriendFeed API, I wanted to retrieve the entries of a FriendFeed room, and then sort the returned entries by the number of comments…

Getting the latest 30 entries is a simple HTTP call.  FriendFeed returns a json structure which is nicely parsed with simplejson (soon to be part of the standard python library).

import simplejson
import urllib2

r = urllib2.urlopen('')
json = simplejson.loads(

# I just want to look at the entries in the room
e = json['entries']

I want to sort the entries by the number of comments.  In other words, I want to use the number of comments as a sort key.  Luckly, Python’s sorted() method has a key attribute, which takes a callable that returns a single value to be used as a key.  We use the operator module in order to generate the sorting key method:

ln = lambda x: len(operator.getitem(x,'comments'))
esorted = sorted(e,key=ln,reverse=True)</code>

for i in esorted:
print i['title'].encode('utf-8'), len(i['comments'])

That took me all morning to get, which shows some of my Python programming limitations.  My first attempt, I tried this:

In [94]: es = sorted(e, key=len(operator.itemgetter('comments')))
TypeError                                 Traceback (most recent call last)

/home/fitzgeraldsteele/<ipython console> in <module>()

TypeError: object of type 'operator.itemgetter' has no len()

Now I recall that an object must have a .__len__() method in order to work with len().  But operator.itemgetter() returns a function, not an object with a .__len__(), hence the TypeError exceptin I got.

Then I tried this:

esorted = sorted(e, key=lambda x: len(operator.getitem(x,'comments')))

Which is very similar to the solution I ended up with, but this one returns the list in different order.  I’m not sure why yet. Update: Duh…we get a different order because the first one has reverse=True, and the second one doesn’t.

About these ads