5

Assume I have a dictionary:

d = {3: 'three', 2: 'two', 1: 'one'}

I want to rearrange the order of this dictionary so that the dictionary is:

d = {1: 'one', 2: 'two', 3: 'three'}

I was thinking something like the reverse() function for lists, but that did not work. Thanks in advance for your answers!

kmario23
  • 57,311
  • 13
  • 161
  • 150
SomeMosa
  • 413
  • 5
  • 28

3 Answers3

14

Since Python 3.8 and above, the items view is iterable in reverse, so you can just do:

d = dict(reversed(d.items()))

On 3.7 and 3.6, they hadn't gotten around to implementing __reversed__ on dict and dict views (issue33462: reversible dict), so use an intermediate list or tuple, which do support reversed iteration:

d = {3: 'three', 2: 'two', 1: 'one'}
d = dict(reversed(list(d.items())))

Pre-3.6, you'd need collections.OrderedDict (both for the input and the output) to achieve the desired result. Plain dicts did not preserve any order until CPython 3.6 (as an implementation detail) and Python 3.7 (as a language guarantee).

wim
  • 338,267
  • 99
  • 616
  • 750
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
2

Standard Python dictionaries (Before Python 3.6) don't have an order and don't guarantee order. This is exactly what the creation of OrderedDict is for.

If your Dictionary was an OrderedDict you could reverse it via:

import collections

mydict = collections.OrderedDict()
mydict['1'] = 'one'
mydict['2'] = 'two'
mydict['3'] = 'three'

collections.OrderedDict(reversed(list(mydict.items())))
Bradd
  • 196
  • 10
  • 2
    Actually, as of 3.6 (CPython/PyPy implementation detail) and 3.7 (as language guarantee) plain `dict` is insertion ordered, just like `OrderedDict`. `OrderedDict` provides a few additional APIs for manipulating the order, but you don't need it for simple reversals. – ShadowRanger Apr 29 '19 at 23:01
  • what makes you think this is wrong? Here's a demo showing that it works: https://repl.it/repls/ExtraneousAllFormula – Bradd Apr 29 '19 at 23:35
  • @Bradd: The wrong part was back when this answer claimed `dict`s were always unordered (when they've been ordered on modern CPython for over two years now). – ShadowRanger Apr 30 '19 at 00:26
1

Another straightforward solution, which is guaranteed to work for Python v3.7 and over:

d = {'A':'a', 'B':'b', 'C':'c', 'D':'d'}
dr = {k: d[k] for k in reversed(d)}

print(dr)

Output:

{'D': 'd', 'C': 'c', 'B': 'b', 'A': 'a'}

Note that reversed dictionaries are still considered equal to their unreversed originals, i.e.:

(d == dr) == True

In response to someone upvoting this comment, I was curious to see which solution is actually faster.

As usual, it depends. Reversing a 10,000 item dictionary 10,000 times is faster with the solution using list and reversed on the items. But reversing a 1,000,000 item dictionary 100 times (i.e. the same number of items in total reversed dictionaries, just a bigger starting dictionary) is faster with the comprehension - it's left up to the reader to find the exact point where it flips. If you deal with large dictionaries, you may want to benchmark either if performance matters:

from random import randint
from timeit import timeit


def f1(d):
    return dict(reversed(list(d.items())))


def f2(d):
    return {k: d[k] for k in reversed(d)}


def compare(n):
    d = {i: randint(1, 100) for i in range(n)}
    print(timeit(lambda: f1(d), number=100000000 // n))
    print(timeit(lambda: f2(d), number=100000000 // n))


compare(10000)
compare(1000000)

Results (one run, typical results):

4.1554735
4.7047593
8.750093200000002
6.7306311
Grismar
  • 27,561
  • 4
  • 31
  • 54