91

The only methods I found work for python2 or return only list of tuples.

Is it possible to sort dictionary, e.g. {"aa": 3, "bb": 4, "cc": 2, "dd": 1}, by its values?

Order of sorted dictionary I want to achieve is from largest to smallest. I want results to look like this:

bb 4
aa 3
cc 2
dd 1

And after sorting I want to store it into a text file.

Salvatore Cosentino
  • 6,663
  • 6
  • 17
  • 25

6 Answers6

126

itemgetter (see other answers) is (as I know) more efficient for large dictionaries but for the common case, I believe that d.get wins. And it does not require an extra import.

>>> d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
>>> for k in sorted(d, key=d.get, reverse=True):
...     k, d[k]
...
('bb', 4)
('aa', 3)
('cc', 2)
('dd', 1)

Note that alternatively you can set d.__getitem__ as key function which may provide a small performance boost over d.get.

SzieberthAdam
  • 3,999
  • 2
  • 23
  • 31
  • 1
    Could you please explain|expand the syntax in line 2? I'm just learning Python 3 and would love to understand this one. – Serge Jan 06 '17 at 15:04
  • 3
    Sure but it would be easier if I would know what you do not understand. `[x for x in iterable]` is a Python List Comprehension (google) which is very common and efficient in Python to create lists. `(k, d[k])` is a two element tuple, the second element (`d[k]`) is the value from the dictionary. `sorted()` is a builtin function returning the keys of the dictionary sorted by the values. Using `key=d.get` it the key of my answer which is not trivial to know. Knowing builtin functions is essential. I hope this helped. – SzieberthAdam Jan 06 '17 at 16:03
  • Thank you! The `[x for x in iterable]` "List comprehension" is what was missing in the intro course. Now reading about it (was hard to find not knowing the name). – Serge Jan 06 '17 at 17:07
  • I made the code more simple with last edit which eliminiated the list comprehension entirely. – SzieberthAdam Jan 21 '21 at 10:03
33
from collections import OrderedDict
from operator import itemgetter    

d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
print(OrderedDict(sorted(d.items(), key = itemgetter(1), reverse = True)))

prints

OrderedDict([('bb', 4), ('aa', 3), ('cc', 2), ('dd', 1)])

Though from your last sentence, it appears that a list of tuples would work just fine, e.g.

from operator import itemgetter  

d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
for key, value in sorted(d.items(), key = itemgetter(1), reverse = True):
    print(key, value)

which prints

bb 4
aa 3
cc 2
dd 1
Davide Fiocco
  • 5,350
  • 5
  • 35
  • 72
Paul Draper
  • 78,542
  • 46
  • 206
  • 285
  • Thanks for your help. I thought that one of the solutions will be something similar to this. –  Jan 06 '14 at 16:38
  • 1
    `dict` keeps insertion order now, so there's no reason to use `OrderedDict` – Boris Verkhovskiy Mar 22 '19 at 04:04
  • 2
    I can think of two reasons, firstly it makes it explicit that you care about order, secondly someone may run your code on an older interpreter amd having it silently misbehave is not a good outcome. – plugwash Jun 08 '19 at 05:15
26

You can sort by values in reverse order (largest to smallest) using a dictionary comprehension:

{k: d[k] for k in sorted(d, key=d.get, reverse=True)}
# {'b': 4, 'a': 3, 'c': 2, 'd': 1}

If you want to sort by values in ascending order (smallest to largest)

{k: d[k] for k in sorted(d, key=d.get)}
# {'d': 1, 'c': 2, 'a': 3, 'b': 4}

If you want to sort by the keys in ascending order

{k: d[k] for k in sorted(d)}
# {'a': 3, 'b': 4, 'c': 2, 'd': 1}

This works on CPython 3.6+ and any implementation of Python 3.7+ because dictionaries keep insertion order.

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
18

Another way is to use a lambda expression. Depending on interpreter version and whether you wish to create a sorted dictionary or sorted key-value tuples (as the OP does), this may even be faster than the accepted answer.

d = {'aa': 3, 'bb': 4, 'cc': 2, 'dd': 1}
s = sorted(d.items(), key=lambda x: x[1], reverse=True)

for k, v in s:
    print(k, v)
Bede Constantinides
  • 2,424
  • 3
  • 25
  • 28
  • 1
    While your code works, I don't think dictionaries are guaranteed to return the items in the same order as added. – Ivan Nov 18 '18 at 19:27
  • 2
    @Ivan Thanks – I've removed the superfluous use of dict() here, although in CPython 3.6+, dict is order-preserving, and this is likely to become a language feature in the near future (https://docs.python.org/3/whatsnew/3.6.html) – Bede Constantinides Nov 21 '18 at 12:41
  • Thanks, it's interesting to know. Also - at the end you can just do `print(s)` instead of a loop :) – Ivan Nov 21 '18 at 12:50
  • @Ivan Of course, but then the code wouldn't produce the output OP has requested… – Bede Constantinides Nov 21 '18 at 13:51
  • 1
    `dict`s preserve order in all Pythons starting with 3.7 – Boris Verkhovskiy Dec 20 '19 at 14:38
  • Your timings are unfair because for your method you're (presumably) timing returning a list of `(key, value)` tuples. If you time returning a dict from both methods: `%timeit {k: d[k] for k in sorted(d, key=d.get, reverse=True)}` vs `%timeit dict(sorted(d.items(), key=lambda x: x[1], reverse=True))`, then *your* method is 10% slower. – Boris Verkhovskiy Nov 14 '20 at 05:43
  • 1
    actually it's less than 10%, I get 54 ms vs 57.3 ms on Python 3.8.6 with a 100,000 element dictionary, but still technically slower. I think you should remove them, it's not a worthwhile optimization. – Boris Verkhovskiy Nov 14 '20 at 05:51
  • @Boris Whether we benchmark reaching a sorted dict or a list of tuples is a matter of interpretation of the OP's question and their desired output: He says "I want results to look like this". However, it appears that as of CPython 3.8, either approach is slower using a lambda expression anyway, and as such I've removed speed claims and timings from my answer. – Bede Constantinides Nov 14 '20 at 18:40
10

To sort dictionary, we could make use of operator module. Here is the operator module documentation.

import operator                             #Importing operator module
dc =  {"aa": 3, "bb": 4, "cc": 2, "dd": 1}  #Dictionary to be sorted

dc_sort = sorted(dc.items(),key = operator.itemgetter(1),reverse = True)
print dc_sort

Output sequence will be a sorted list :

[('bb', 4), ('aa', 3), ('cc', 2), ('dd', 1)]

If we want to sort with respect to keys, we can make use of

dc_sort = sorted(dc.items(),key = operator.itemgetter(0),reverse = True)

Output sequence will be :

[('dd', 1), ('cc', 2), ('bb', 4), ('aa', 3)]
Reck
  • 1,388
  • 11
  • 20
0

To sort a dictionary and keep it functioning as a dictionary afterwards, you could use OrderedDict from the standard library.

If that's not what you need, then I encourage you to reconsider the sort functions that leave you with a list of tuples. What output did you want, if not an ordered list of key-value pairs (tuples)?

Andrew Gorcester
  • 19,595
  • 7
  • 57
  • 73