How to Sort a List, Tuple or Object (with sorted) in Python

Sorting a list or tuple is easy in Python! Since a tuple is basically like an array that is not modifiable, we'll treat it almost the same as a list.

Sorting a Python List the Simple Way

Okay, so if you only want to sort a list of numbers, Python has a built in function that does all the hard work for you.

Say we have a list of numbers:

1

>>>a=[3,6,8,2,78,1,23,45,9]

And we want to sort them in ascending order. All we do is call sort on the list, for in-place sorting, or the built in function sorted for not modifying the original list and returning a new sorted list. Both functions take in the same arguments and can be treated as "the same" for our purposes here, except for the reason above.

Here we go:

1

2

3

4

5

6

>>>sorted(a)

[1,2,3,6,8,9,23,45,78]

>>>

>>>a.sort()

>>>a

[1,2,3,6,8,9,23,45,78]

What about descending order?

Here you go:

1

2

3

4

5

>>>sorted(a,reverse=True)

[78,45,23,9,8,6,3,2,1]

>>>a.sort(reverse=True)

>>>l

[78,45,23,9,8,6,3,2,1]

What is Python doing behind the scenes? It's calling a version of mergesort on the list. It calls the function __cmp__ on each object when comparing values, and decides which one to put in front of the other based on the value returned from __cmp__. The return value is 0 for equal to, 1 for greater than, and -1 for less than the compared value. We'll use this information later to make our own objects sortable.

What about tuples, you say? I'm getting to that.

Sorting a Python Tuple the Simple Way

Since tuples are arrays that you cannot modify, they don't have an in-place sort function that can be called directly on them. They must always use the sorted function to return a sorted list. Keeping that in mind, here's how to do it:

1

2

3

>>>tup=(3,6,8,2,78,1,23,45,9)

>>>sorted(tup)

[1,2,3,6,8,9,23,45,78]

Notice how sorted returns an array.

Okay, now let's see how to sort something a little more complicated.

Sorting a List of Lists or Tuples

This is a little more complicated, but still pretty easy, so don't fret! Both the sorted function and the sort function take in a keyword argument called key.

What key does is it provides a way to specify a function that returns what you would like your items sorted by. The function gets an "invisible" argument passed to it that represents an item in the list, and returns a value that you would like to be the item's "key" for sorting.

So, taking a new list, let's test it out by sorting by the first item in each sub-list:

1

2

3

4

5

>>>defgetKey(item):

...returnitem[0]

>>>l=[[2,3],[6,7],[3,34],[24,64],[1,43]]

>>>sorted(l,key=getKey)

[[1,43],[2,3],[3,34],[6,7],[24,64]]

Here we can see that the list is now sorted by the first item in the sub-list in ascending order. Note that you could have used the sort function as well, but I personally like the sorted function better, so I'll be using that in further examples.

What happened? Remember that "invisible" argument I was talking about? That's what gets passed into the getKey function every time the sorted needs a value. Tricky, tricky python ;).

Sorting by the second item in each sub-list would be as simple as changing the getKey function to this:

1

2

defgetKey(item):

returnitem[1]

Alright. All good. Now, what about a list of tuples? Glad you asked!

It's actually the exact same as our example above, but has the list defined as such:

1

2

3

>>>a=[(2,3),(6,7),(3,34),(24,64),(1,43)]

>>>sorted(l,key=getKey)

[(1,43),(2,3),(3,34),(6,7),(24,64)]

The only thing that has changed is that we now get a list of tuples instead of a list of lists returned to us.

The exact same solution can be applied to a tuple of tuples, so I'm not going to go there, as that would just be redundant. It would also waste more of those digital trees that make this beautiful digital paper.

Sorting a List (or Tuple) of Custom Python Objects

Here's a custom object that I created:

1

2

3

4

classCustom(object):

def__init__(self,name,number):

self.name=name

self.number=number

Let's make a list of them, for sorting purposes:

1

2

3

4

5

6

customlist=[

Custom('object',99),

Custom('michael',1),

Custom('theodore the great',59),

Custom('life',42)

]

Okay, so we've got all of our fancy new custom objects in a list and we want to be able to sort them. How do we do that?

Well, we could define a function, like we did above, that takes in the item and returns a list. So let's do that.

1

2

defgetKey(custom):

returncustom.number

This one is a little different, because our object is not a list anymore. This allows us to sort by the number property in the custom object.

So if we run the sorted function on our list of fancy custom objects, we get this:

1

2

3

4

5

>>>sorted(customlist,key=getKey)

[<__main__.Custom objectat0x7f64660cdfd0>,

<__main__.Custom objectat0x7f64660d5050>,

<__main__.Custom objectat0x7f64660d5090>,

<__main__.Custom objectat0x7f64660d50d0>]

A big mess of ugliness that we don't understand. Perfect. But don't worry, dear viewer, there is a simple fix we can apply to our custom object to make it all better!

Let's redefine our object class like this:

1

2

3

4

5

6

7

8

9

classCustom(object):

def__init__(self,name,number):

self.name=name

self.number=number

def__repr__(self):

return'{}: {} {}'.format(self.__class__.__name__,

self.name,

self.number)

Ok, what the heck did we just do? First, the __repr__ function tells Python how we want the object to be represented as. In more complex terms, it tells the interpreter how to display the object when it is printed to the screen.

So, we tell Python to represent the object by it's class name, name, and number.

Now lets try sorting it again:

1

2

3

>>>sorted(customlist,key=getKey)

[Custom:michael1,Custom:life42,

Custom:theodore the great59,Custom:object99]

That's much better! Now we can actually tell that it sorted properly!

But there's a little bit of a problem. It's just nit-picking, but I don't want to have to type that key keyword every time I call sorted.

So, how do I do that? Well, remember that __cmp__ function I told you about? Let's put it into action!

Let's redefine our object one more time like this:

1

2

3

4

5

6

7

8

9

10

11

12

13

classCustom(object):

def__init__(self,name,number):

self.name=name

self.number=number

def__repr__(self):

return'{}: {} {}'.format(self.__class__.__name__,

self.name,

self.number)

def__cmp__(self,other):

ifhasattr(other,'number'):

returnself.number.__cmp__(other.number)

Looking good. What this does is tell Python to compare the value of the current object to another object in the list to see how it compares. Like I said above, the sorted function will call the __cmp__ function on the objects it is sorting in order to determine where they should be in relation to other objects.

Now we can just call sorted without worrying about including the key keyword, like so:

1

2

>>>sorted(customlist)

[Custom:michael1,Custom:life42,Custom:theodore the great59,Custom:object99]

And voilà! It works nicely. Please note that all of the above also applies to tuples of the custom object. But I like to save my digital trees, as you know.

Sorting a Heterogeneous List of Custom Python Objects

Alright. Since Python is a dynamic language, it doesn't so much care about what objects we throw into lists. They can all be the same type, or they can all be different.

So let's define another different object to use with our Custom object.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

classAnotherObject(object):

def__init__(self,tag,age,rate):

self.tag=tag

self.age=age

self.rate=rate

def__repr__(self):

return'{}: {} {} {}'.format(self.__class__.__name__,

self.tag,

self.age,self.rate)

def__cmp__(self,other):

ifhasattr(other,'age'):

returnself.age.__cmp__(other.age)

It's a similar object, but still different from our Custom object.

Let's make a list of these and our Custom objects:

1

2

3

4

5

6

7

8

9

customlist=[

Custom('object',99),

Custom('michael',1),

Custom('theodore the great',59),

Custom('life',42),

AnotherObject('bananas',37,2.2),

AnotherObject('pants',73,5.6),

AnotherObject('lemur',44,9.2)

]

Now if we try to run sorted on this list:

1

2

3

4

>>>sorted(customlist)

Traceback(most recent call last):

File"<stdin>",line1,in<module>

TypeError:an integer isrequired

We get a lovely error. Why? Because Custom doesn't have an attribute called age and AnotherObject doesn't have an attribute called number.

What do we do? Panic!

Just kidding. We know what to do. Let's redefine those objects again!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

classCustom(object):

def__init__(self,name,number):

self.name=name

self.number=number

def__repr__(self):

return'{}: {} {}'.format(self.__class__.__name__,

self.name,

self.number)

def__cmp__(self,other):

ifhasattr(other,'getKey'):

returnself.getKey().__cmp__(other.getKey())

defgetKey(self):

returnself.number

classAnotherObject(object):

def__init__(self,tag,age,rate):

self.tag=tag

self.age=age

self.rate=rate

def__repr__(self):

return'{}: {} {} {}'.format(self.__class__.__name__,

self.tag,

self.age,self.rate)

def__cmp__(self,other):

ifhasattr(other,'getKey'):

returnself.getKey().__cmp__(other.getKey())

defgetKey(self):

returnself.age

Awesome! What did we just do? We defined a common getKey function that both of the objects have so that we can compare them easily.

So now if we run the sorted function again, we get:

1

2

3

4

5

>>>sorted(customlist)

[Custom:michael1,AnotherObject:bananas372.2,

Custom:life42,AnotherObject:lemur449.2,

Custom:theodore the great59,AnotherObject:pants735.6,

Custom:object99]

Nice! Now our objects can be compared and sorted to their hearts content.

You still prefer the using the key keyword, you say?

You can do that too. If you leave out the __cmp__ functions in each object, and define an outside function like so:

1

2

defgetKey(customobj):

returncustomobj.getKey()

And then call sorted like so:

1

2

3

4

5

>>>sorted(customlist,key=getKey)

[Custom:michael1,AnotherObject:bananas372.2,

Custom:life42,AnotherObject:lemur449.2,

Custom:theodore the great59,AnotherObject:pants735.6,

Custom:object99]

And there you have it! Pretty straight forward, but not as straight forward as some might guess. Still, Python makes it pretty easy with its built in sorted function.

If you need to sort often, consider using a sorted container type. There’s a Python package called sortedcontainers that contains pure-Python, fast (as in fast-as-C) implementations of SortedList, SortedDict, and SortedSet types.

kchrisc

Joey, Thanks for the article. It helped me solve a sort problem that I was having with sorting on an array.

I do have one question, why does a function (getKey) for sorting on a key have to be made? One would think that there would be a built-in way.

Thanks,

K. Chris C.

http://jacksonc.com Jackson Cooper

Hi Chris. Basically when you sort a list of things, you need a definitive way to know which is greater and which is less than the others. The custom sort function essentially returns the “definitive value” of an item. For simple things like numbers and strings, a custom sort function is not needed and this all comes built in. Say I had a class Teacher, and an array containing a list of Teacher instances. Each teacher’s wage was based on 1) their years of experience 2) whether they’re casual, temporary, or permanent 3) how many hours they worked that week. And you wanted to order every teacher by their wage. This is where the custom function comes into play. It would read the instance variables, and return an integer representing that teacher.

In your case you’re only wanting to compare items with the second index within the item. You could get away without using a function, and instead use a lambda, or an anonymous function. In your case it would look like this: v_Array.sort(key=lambda i: i[1]). Check out this article for another example. Hope that helps :).

K. Chris C.

Thanks for the reply. I was sort of forced to learn “lambda” when learning Tkinter–To use a arg. passing function as a command in a button, lambda must be used. I then learned to use it with “map” and to create “jump tables.” “Jump tables” basically allow you to select expressions from a list or possible an array. Cool.