Python Dictionary Order

1553
8
07-23-2014 07:22 PM
XanderBakker
Esri Esteemed Contributor
3 8 1,553

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

Tags (1)
8 Comments
About the Author
Solution Engineer for the Utilities Sector @ Esri Colombia - Ecuador - Panamá sr GIS Advisor / Python - Arcpy developer / GIS analyst / technical project leader / lecturer and GeoNet moderator, focusing on innovations in the field of GIS. Specialties: ArcGIS, Python, ArcGIS Enterprise, ArcGIS Online, Arcade, Configurable Apps, WAB, Mobile Apps, Insights, Spatial Analysis, LiDAR / 3D Laser Scanning / Point Clouds. UNME http://nl.linkedin.com/in/xanderbakker/ http://www.slideshare.net/XanderBakker http://www.scribd.com/xbakker http://twitter.com/#!/XanderBakker
Labels