28

Here is the dictionary looks like:

{'57481': 50, '57480': 89, '57483': 110, '57482': 18, '57485': 82, '57484': 40}  

I would like to sort the dictionary in numerical order, the result should be:

{'57480': 89, '57481': 50, '57482': 18, '57483': 110, '57484': 40, '57485': 82} 

I tried sorted(self.docs_info.items) but it doesn't work.

Ronikos
  • 437
  • 1
  • 6
  • 18
Justin
  • 2,765
  • 6
  • 24
  • 25
  • 1
    possible duplicate of [python dictionary sort by key](http://stackoverflow.com/questions/9001509/python-dictionary-sort-by-key) – alecxe Mar 08 '14 at 04:18
  • Does this answer your question? [How can I sort a dictionary by key?](https://stackoverflow.com/questions/9001509/how-can-i-sort-a-dictionary-by-key) – Vega Feb 17 '20 at 04:33

4 Answers4

27

If you only need to sort by key, you're 95% there already. Assuming your dictionary seems to be called docs_info:

for key, value in sorted(docs_info.items()): # Note the () after items!
    print(key, value)

Since dictionary keys are always unique, calling sorted on docs_info.items() (which is a sequence of tuples) is equivalent to sorting only by the keys.

Do bear in mind that strings containing numbers sort unintuitively! e.g. "11" is "smaller" than "2". If you need them sorted numerically, I recommend making the keys int instead of str; e.g.

int_docs_info = {int(k) : v for k, v in docss_info.items()}

This of course just changes the order in which you access the dictionary elements, which is usually sufficient (since if you're not accessing it, what does it matter if it's sorted?). If for some reason you need the dict itself to be "sorted", then you'll have to use collections.OrderedDict, which remembers the order in which items were inserted into it. So you could first sort your dictionary (as above) and then create an OrderedDict from the sorted (key, value) pairs:

sorted_docs_info = collections.OrderedDict(sorted(docs_info.items()))
Henry Keiter
  • 16,863
  • 7
  • 51
  • 80
  • how would you change this answer for multidimensional dicts? eg 4 dimensional dictionary like ```docs_info{1:{2:{3:{55555}}}}``` – ulkas Feb 08 '19 at 15:30
  • @ulkas Pull out any subdict and sort it like any other. If you're hoping to flatten it to a single dimension, do that first and sort it later. The flattening logic will be more complex than any sorting behavior you implement. – Henry Keiter Feb 11 '19 at 07:11
10

Standard Python dicts are "unordered". You can use an OrderedDict, take a look at the docs:

from collections import OrderedDict

d = {'57481': 50, '57480': 89, '57483': 110, '57482': 18, '57485': 82, '57484': 40}
OrderedDict(sorted(d.items(), key=lambda t: t[0]))
# OrderedDict([('57480', 89), ('57481', 50), ('57482', 18), ('57483', 110), ('57484', 40), ('57485', 82)])
elyase
  • 39,479
  • 12
  • 112
  • 119
  • `lambda x: 2*x+1` is practically the same as `def f(x): return 2*x+1 `. I used it as a shorter way to write a function that selects the first element in a tuple(the key). – elyase Mar 08 '14 at 04:28
5

If repeatedly sorting elements and inserting them in an ordered dict is too slow, consider one of the sorted dict implementations on PyPI. A SortedDict data type efficiently maintains its keys in sorted order. The sortedcontainers module contains one such implementation.

Installation from PyPI is easy:

pip install sortedcontainers

If you can't pip install then simply copy down the sortedlist.py and sorteddict.py files from the open-source repository. SortedContainers is implemented in pure-Python but is fast-as-C implementations.

Once installed simply:

In [1]: from sortedcontainers import SortedDict

In [6]: SortedDict({'57481': 50, '57480': 89, '57483': 110, '57482': 18, '57485': 82, '57484': 40})
Out[6]: SortedDict({'57480': 89, '57481': 50, '57482': 18, '57483': 110, '57484': 40, '57485': 82})

The sortedcontainers module also maintains a performance comparison of several popular implementations.

GrantJ
  • 8,162
  • 3
  • 52
  • 46
4

In Python 3 sorted() has an optional parameter key. And in 3.6+ dict maintains insertion order.

key specifies a function of one argument that is used to extract a comparison key from each element in iterable (for example, key=str.lower). The default value is None (compare the elements directly).

Therefore, what OP wants can be accomplished this way.

>>> d = {'57481': 50, '57480': 89, '57483': 110, '57482': 18, '57485': 82, '57484': 40}
>>> for key, value in sorted(d.items(), key=lambda item: int(item[0])):
...     print(key, value)
57480 89
57481 50
57482 18
57483 110
57484 40
57485 82

Or if OP wants to create a new sorted dictionary.

>>> d = {'57481': 50, '57480': 89, '57483': 110, '57482': 18, '57485': 82, '57484': 40}
>>> d_sorted = {key:value for key, value in sorted(d.items(), key=lambda item: int(item[0]))}
>>> d_sorted
{'57480': 89, '57481': 50, '57482': 18, '57483': 110, '57484': 40, '57485': 82}

d.items() returns a list of tuples, e.g. ('57480': 89) and so on. The lambda functions takes this tuple and applies int function to the first value. And then the result is used for comparison.

K.Novichikhin
  • 339
  • 2
  • 8