Sorting a List of Objects by an Attribute of the Objects
Credit: Yakov Markovitch, Nick Perkins
Problem
You have a list of objects that you need to sort according to one attribute of each object, as rapidly and portably as possible.
Solution
In this case, the obvious approach is concise, but quite slow:
def sort_by_attr_slow(seq, attr):
def cmp_by_attr(x, y, attr=attr):
return cmp(getattr(x, attr), getattr(y, attr))
seq.sort(cmp_by_attr)There is a faster way, with DSU:
def sort_by_attr(seq, attr):
import operator
intermed = map(None, map(getattr, seq, (attr,)*len(seq)),
xrange(len(seq)), seq)
intermed.sort( )
return map(operator.getitem, intermed, (-1,)*len(intermed))
def sort_by_attr_inplace(lst, attr):
lst[:] = sort_by_attr(lst, attr)Discussion
Sorting a list of objects by an attribute of each object is best done
using the DSU idiom. Since this recipe uses only built-ins and
doesn’t use explicit looping, it is quite fast.
Moreover, the recipe doesn’t use any Python
2.0-specific features (such as zip or list
comprehensions), so it can be used for Python 1.5.2 as well.
List comprehensions are neater, but this recipe demonstrates that you
can do without them, if and when you desperately need portability to
stone-age Python installations. Of course, the correct use of
map can be tricky. Here, for example, when we
build the auxiliary list intermed, we need to call
the built-in function getattr on each item of
sequence seq using the same string,
attr, as the second argument in each case. ...