[Tutor] sorting objects on two attributes

Kent Johnson kent37 at tds.net
Mon Mar 3 17:00:20 CET 2008


Eric Abrahamsen wrote:

> I have a list of objects, each of which has two attributes, object_id  
> and submit_date. What I want is to sort them by content_type, then by  
> submit_date within content_type, and then sort each content_type block  
> according to which block has the newest object by submit_date. (This  
> sequence of sorting might not be optimal, I'm not sure). I'm actually  
> creating a list of recent comments on blog entries for a python-based  
> web framework, and want to arrange the comments according to blog  
> entry (content_type), by submit_date within that entry, with the  
> entries with the newest comments showing up on top.

This description doesn't match your code. There is no content_type in 
the code.

I think what you want to do is group the comments by object_id, sort 
within each object_id group by submit_date, then sort the groups by most 
recent submit date.

> I don't believe a single cmp function fed to list.sort() can do this,  
> because you can't know how two objects should be compared until you  
> know all the values for all the objects. I'd be happy to be proven  
> wrong here.

Django's SortedDict might help. Perhaps this:

from operator import attrgetter
from django.utils.datastructures import SortedDict

sd = SortedDict()
for com in sorted(queryset, key=attrgetter.submit_date, reverse=True):
   sd.setdefault(com.object.id, []).append(com)


Now sd.keys() is a list of object_ids in descending order by most recent 
comment, and sd[object_id] is a list of comments for object_id, also in 
descending order by submit_date. If you want the comments in increasing 
date order (which I think your code below does) then you have to reverse 
the lists of comments, e.g.
   for l in sd.values():
     l.reverse()

or just reverse at the point of use with the reversed() iterator.

> def make_com_list(queryset):
>     ids = set([com.object_id for com in queryset])
>     xlist = [[com for com in queryset if com.object_id == i] for i in  
> ids]
>     for ls in xlist:
>         ls.sort(key=lambda x: x.submit_date)
>     xlist.sort(key=lambda x: max([com.submit_date for com in x]),  
> reverse=True)

No need for max() since the list is sorted; use
   key=lambda x: x[-1].submit_date

Kent


More information about the Tutor mailing list