xander_bakker

Python Dictionary Order

Blog Post created by xander_bakker on Jul 23, 2014

When you create a dictionary in Python the order will not necessary be the order in which you create it. There is a solution for this and that is the use of an OrderedDict (can be found in the collections module).

 

Take the following example; you have a dictionary you want to use to classify an angle (0-360) into a cardinal direction. You define the dictionary, but if you print the dictionary directly afterwards you will notice that the order is not necessary the same as defined:

 

dctCard = {22.5:"E", 67.5: "NE", 112.5: "N",
           157.5: "NW", 202.5: "W", 247.5: "SW",
           292.5: "S", 337.5: "SE", 360: "E"}

print dctCard

 

results in:

 

>> {22.5: 'E', 67.5: 'NE', 247.5: 'SW', 202.5: 'W', 292.5: 'S', 112.5: 'N', 360: 'E', 337.5: 'SE', 157.5: 'NW'}

 

So if you would use code like below to obtain the cardinal direction based on an angle, this will give erroneous results:

 

dctCard = {22.5:"E", 67.5: "NE", 112.5: "N",
           157.5: "NW", 202.5: "W", 247.5: "SW",
           292.5: "S", 337.5: "SE", 360: "E"}

myangle = 75

for angle, cardinal in dctCard.items():
    if myangle < angle:
        result = cardinal
        break

print "Angle {0} gives {1}".format(myangle, result)

 

could result in:

 

>> Angle 75 gives SW

 

 

Ordered dictionary

It is possible to solve this by using collections.OrderedDict(). Please be aware that the code below will still result in a randomly sorted dictionary:

 

from collections import OrderedDict
dctCard = OrderedDict({22.5:"E", 67.5: "NE", 112.5: "N",
           157.5: "NW", 202.5: "W", 247.5: "SW",
           292.5: "S", 337.5: "SE", 360: "E"})

 

The reason is, that first the dictionary is created in a random order and than that random order is stored as "ordered". There are two ways of solving this.

 

Either you loop through a sorted list of keys (the angle values):

 

dctCard = {22.5:"E", 67.5: "NE", 112.5: "N",
           157.5: "NW", 202.5: "W", 247.5: "SW",
           292.5: "S", 337.5: "SE", 360: "E"}

myangle = 75

for angle in sorted(dctCard.keys()):
    if myangle < angle:
        result = dctCard[angle]
        break

 

Or you create a list of key value pairs and convert that to OrderedDict

 

from collections import OrderedDict

lstCardinal = [(22.5,"E"), (67.5, "NE"), (112.5, "N"),
               (157.5, "NW"), (202.5, "W"), (247.5, "SW"),
               (292.5, "S"), (337.5, "SE"), (360, "E")]

dctCard2 = OrderedDict(lstCardinal)

myangle = 75

for angle, cardinal in dctCard2.items():
    if myangle < angle:
        result = cardinal
        break

Outcomes