103

I have a list of class instances -

x = [<iteminstance1>,...]

among other attributes the class has score attribute. How can I sort the items in ascending order based on this parameter?

EDIT: The list in python has something called sort. Could I use this here? How do I direct this function to use my score attribute?

2 Answers2

227

In addition to the solution you accepted, you could also implement the special __lt__() ("less than") method on the class. The sort() method (and the sorted() function) will then be able to compare the objects, and thereby sort them. This works best when you will only ever sort them on this attribute, however.

class Foo(object):

     def __init__(self, score):
         self.score = score

     def __lt__(self, other):
         return self.score < other.score

l = [Foo(3), Foo(1), Foo(2)]
l.sort()
kindall
  • 178,883
  • 35
  • 278
  • 309
  • 3
    This is particularly useful if you don't have access to sorted function. This happens when sorted is called by some other modules such as the standard library modules. Example - `priorityqueue` in `queue` calls sorted for the items you supply. – Renae Lider Jul 14 '15 at 07:23
  • 1
    What if we have instances with 2 params like Foo['abc',3] – Bimlesh Sharma Apr 25 '17 at 05:50
  • 6
    @BimleshSharma Then write your `__lt__` method according to how you want your instances to compare, e.g. `return (self.text, self.num) < (other.text, other.num)`. – kindall Apr 26 '17 at 17:39
  • 6
    It took me a moment to figure that `list.sort()` sorts the existing list (and returns `NoneType`), while `sorted(list)` returns the sorted copy of the list. – Kamil S Jaron May 12 '20 at 13:00
  • Also very useful is you have seriously nested data. Having something of type `[(Foo,Bar)]` makes something like `sort()` really tricky otherwise. – Shaavin Apr 02 '21 at 03:21
151
import operator
sorted_x = sorted(x, key=operator.attrgetter('score'))

if you want to sort x in-place, you can also:

x.sort(key=operator.attrgetter('score'))
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • 2
    wow! is it that simple!! Just checked. It is :) –  Oct 24 '10 at 20:37
  • 8
    Welcome to Python! For sake of completness: the "key" parameter to srot functions/methods accepts a function as its parameter. The operator module provides usefull functions to tasks that are ordinarily done by the language Syntax itself - like an "add" function to do the same the " + " token does in the language, and in this case the attrgetter to do the same the " . " connector does in the syntax. Other parameters to "key" can be inplace functions defined with "lambda". In this case, sorted_x = sorted(x, lambda x: x.score)) - would have worked as well. The given example is better, though. – jsbueno Oct 24 '10 at 20:44
  • 3
    I'm not sure using `attrgetter` is better. Lambdas seems to be just as fast, and look cleaner IMO. – adw Oct 24 '10 at 20:51
  • This is just great. Thanks for the question and the answer likewise! – LarsVegas Jul 05 '12 at 13:51
  • sometimes python's simplicity scares me – lucastamoios Sep 06 '15 at 18:36
  • 1
    That wasn't working for me, this worked better: http://www.learningaboutelectronics.com/Articles/How-to-sort-objects-of-a-class-in-Python.php Use: `sorted(list, function)` – camposer Apr 15 '21 at 10:20