By definition, dictionary are not sorted (to speed up access). Let us consider the following dictionary, which stores the age of several persons as values:

1 |
d = {"Pierre": 42, "Anne": 33, "Zoe": 24} |

If you want to sort this dictionary by values (i.e., the age), you must use another data structure such as a list, or an ordered dictionary.

### Use the sorted function and operator module

1 2 |
import operator sorted_d = sorted(d.items(), key=operator.itemgetter(1)) |

Sorted_d is a list of tuples sorted by the second element in each tuple. Each tuple contains the key and value for each item found in the dictionary. If you look at the content of this variable, you should see:

1 |
[ ('Zoe', 24), ('Anne', 33), ('Pierre', 42)] |

### Use the sorted function and lambda function

If you do not want to use the operator module, you can use a lambda function:

1 2 3 |
sorted_d = sorted(d.items(), key=lambda x: x[1]) # equivalent version # sorted_d = sorted(d.items(), key=lambda (k,v): v) |

The computation time is of the same order of magnitude as with the operator module. Would be interesting to test on large dictionaries.

### Use the sorted function and return an ordered dictionary

In the previous methods, the returned objects are list of tuples. So we do not have a dictionary anymore. You can use an OrderedDict if you prefer:

1 2 3 4 |
>>> from collections import OrderedDict >>> dd = OrderedDict(sorted(d.items(), key=lambda x: x[1])) >>> print(dd) OrderedDict([('Pierre', 24), ('Anne', 33), ('Zoe', 42)]) |

### Use sorted function and list comprehension

Another method consists in using list comprehension and use the sorted function on the tuples made of (value, key).

1 |
sorted_d = sorted((value, key) for (key,value) in d.items()) |

Here the output is a list of tuples where each tuple contains the value and then the key:

1 |
[(24, 'Pierre'), (33, 'Anne'), (42, 'Zoe')] |

### A note about Python 3.6 native sorting

In previous version on this post, I wrote that “In Python 3.6, the iteration through a dictionary is sorted.”. This is wrong. What I meant is that in Python 3.6 **dictionary keeps insertion sorted**.

It means that if you insert your items already sorted, the new python 3.6 implementation will be this information. Therefore, there is no need to sort the items anymore. Of course, if you insert the items randomly, you will still need to use one of the method mentioned above.

For instance, taking care of the age, we now create our list as follows (sorting by ascending age):

1 2 3 |
d = {("Zoe": 24)} d.update({'Anne': 33}) d.update({'Pierre': 42}) |

Now you can iterate through the items and they will be in the same order as in the creation of the dictionary. So you can just create a list from your items very easily:

1 2 |
list(d.items()) Out[15]: [('Zoe', 24), ('Anne', 33), ('Pierre', 42)] |

### Benchmark

Here is a quick benchmark made using the small dictionary from the above examples. Would be interesting to redo the test with a large dictionary.

What you can see is that the native Python dictionary sorting is pretty cool followed by the combination of the lambda + list comprehension method. Overall using one of these methods would be equivalent though (factor 2/3 at most).

This image was created with the following code.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import operator import pylab from easydev import Timer times1, times2, times3 = [], [], [] pylab.clf() d = {"Pierre": 42, "Anne": 33, "Zoe": 24} for j in range(20): N = 1000000 with Timer(times3): for i in range(N): sorted_d = sorted((key, value) for (key,value) in d.items()) with Timer(times2): for i in range(N): sorted_d = sorted(d.items(), key=lambda x: x[1]) with Timer(times1): for i in range(N): sorted_d = sorted(d.items(), key=operator.itemgetter(1)) print(j) pylab.boxplot([times1, times2, times3]) pylab.xticks([1,2,3], ["operator", "lambda", "list comprehension and lambda"]) pylab.ylabel("Time (seconds) 1 million sorting \n (repeated 20 times)") pylab.grid() pylab.title("Performance sorted dictionary by values") |

In the py36 example, you’re not actually sorting anything, which is why it’s significantly faster.

Hello,

the python36 way doesn’t seem to sort. I am using ipython3:

> import import sys

> sys.version

‘3.6.6 (default, Jul 19 2018, 14:25:17) \n[GCC 8.1.1 20180712 (Red Hat 8.1.1-5)]’

> d = {“Pierre”: 42, “Anne”: 33, “Zoe”: 24}

> sorted_d = [(k,v) for k,v in d.items()]

> print(sorted_d)

[(‘Pierre’, 42), (‘Anne’, 33), (‘Zoe’, 24)]

What is wrong?

Thank you

Looking back at this post, I don’t know why I wrote that py36 was sorting natively. This is wrong indeed.

What’s important to know about Python 3.6 and above is that dictionary keeps insertion sorted.

So if the dictionary is not sorted, which is the case in this example, well the dictionary is not sorted ! So, you still need to use one of the sorting method explained in the text. However, if you took care of inserting items already sorted, then there is nothing to do, you can iterate through the dictionary in the same order. See the updated post and thanks for reporting this error.

I think you do:

sorted_d = [(k,v) for k,v in d.items()]

According to the article, it should be:

sorted_d = [(v,k) for k,v in d.items()]

v,k not k,v in the first tuple.