0

I have values in a dictionary I would like to sort, so I wrote some code which would pull it all apart, sort as a list, then put back together in another dictionary. However, I have found that even though the values are sorted, as soon as I put it back into a dictionary, it unsorts itself again. I tried with a much simpler example and the same thing happens, and I'm fairly sure it's probably something I've overlooked, but can't figure it out so a bit of help would be appreciated.

Simple version

a = dict()
b = dict()

a['test3'] = 3
a['test2'] = 0
a['test5'] = 4

alist = a.keys()
alist.sort()

for i in range( len( alist ) ):
    b[alist[i]] = a[alist[i]]
    #result of alist[i] is test2, test3, test5 - b has values assigned in order this time

print b
#b is the exact same as a

And the version I'm actually using (put a lot of #'s near the problem bit). The objValues variable is sorted, but as soon as the keys are pulled from it for edgeValues, they are unsorted again.
For a basic idea of what I'm doing, I'm attempting to make some sort of modular thing where you can make a square (bear in mind this is the very first version), and give each edge a name, where it'll connect to other similar edges, so for example, you may have a river flowing between squares, or a road or building.

The current dictionary style is like this, hence why I need the 3 levels of sorting

edgename:{ objectname: [list of sides], objectname: [list of sides]...


def ph_getStoredInfo():
    #process stored values
    objValues = dict()

    #just so it will work with copy + paste
    allEdges = []
    allEdges.append ( [['test4'], ['pCube1', 'x'], ['pCube1', 'y'], ['pCube1', '-y'], ['pCube1', '-x'], ['pCube2', '-x']] )
    allEdges.append ( [['test2'], ['pCube2', '-x'], ['pCube2', 'x']] )
    allEdges.append ( [['test3'], ['pCube2', '-x'], ['pCube2', 'x']] )

    for i in range( len( allEdges ) ):
        edgeName = allEdges[i][0][0]
        objValues[edgeName] = dict()
        for j in range( len( allEdges[i] )-1 ):
            objInfo = allEdges[i][j+1]
            if objValues[edgeName].get(objInfo[0]) == None:
                objValues[edgeName][objInfo[0]] = [objInfo[1]]
            else:
                objValues[edgeName][objInfo[0]].append( objInfo[1] )
    #sort all values
    sortedList = dict()
    edgeValues = objValues.keys()
    edgeValues.sort()
    for i in range( len( edgeValues ) ):
        objNames = objValues[edgeValues[i]].keys()
        objNames.sort()
        sortedList[edgeValues[i]] = dict()
        for j in range( len( objNames ) ):
            objSides = objValues[edgeValues[i]][objNames[j]]
            objSides.sort()
            sortedList[edgeValues[i]][objNames[j]] = dict()
            for m in range( len( objSides ) ):
                if len( sortedList[edgeValues[i]][objNames[j]] ) == 0:
                    sortedList[edgeValues[i]][objNames[j]] = [objSides[m]]
                else:
                    sortedList[edgeValues[i]][objNames[j]].append( objSides[m] )
    return sortedList

#display text
objValues = ph_getStoredInfo()
#####################BIT THAT DOESN'T WORK######################
edgeValues = objValues.keys()
################################################################
for i in range( len( edgeValues ) ):
    objNames = objValues[edgeValues[i]].keys()
    outputText = "Edge '" + str( edgeValues[i] ) + "' is applied to '"
    for j in range( len( objNames ) ):
        outputText += objNames[j] + "' for side"
        objSides = objValues[edgeValues[i]][objNames[j]]
        if len( objSides ) > 1:
            outputText += "s"
        for m in range( len( objSides ) ):
            outputText += " " + objSides[m]
            if m == len( objSides )-2:
                outputText += " and"
            if m < len( objSides )-2:
                outputText += ","
        if j == len( objNames )-2:
            outputText += " and '"
        if j < len( objNames )-2:
            outputText += ", '"
    print outputText
Peter
  • 3,186
  • 3
  • 26
  • 59
  • Dictionaries *are unordered*. – Martijn Pieters May 31 '14 at 17:27
  • 1
    Dictionaries are always unordered. If you want a dictionary to retain the order of the elements as they were added to it, use a [`collections.OrderedDict`](http://docs.python.org/2/library/collections.html#collections.OrderedDict). – Tim Pietzcker May 31 '14 at 17:28

2 Answers2

2

Dictionaries in Python are unordered.

Quoting from the docs:

It is best to think of a dictionary as an unordered set of key: value pairs, with the requirement that the keys are unique (within one dictionary).

Warning: Many a new Pythonistas sits down and experiment and discovers that for a few insertions / deletions dicts with integer keys the dict seem to maintain their order:

>>> d={1:1, 2:2, 3:3, 4:4}
>>> d
{1: 1, 2: 2, 3: 3, 4: 4}
>>> d[2]=20
>>> d
{1: 1, 2: 20, 3: 3, 4: 4}
>>> del d[2]
>>> d
{1: 1, 3: 3, 4: 4}
>>> d[20]=2
>>> d
{1: 1, 3: 3, 4: 4, 20: 2}

First, this is an unpredictable implementation artifact on some versions. Second, it does not always hold true:

>>> for i in range(0,6): d[10**i] = 'power of ten'
... 
>>> d
{100000: 'power of ten', 1: 'power of ten', 100: 'power of ten', 1000: 'power of ten', 10: 'power of ten', 10000: 'power of ten'}

So don't make that mistake.

You can use the dict subclass OrderedDict to maintain insertion order and hence store your unordered dict in the order you want:

from collections import OrderedDict

a = dict()
b = OrderedDict()

a['test3'] = 3
a['test2'] = 0
a['test5'] = 4

for k, v in sorted(a.items(), key=lambda t: t[1]):
    b[k]=v

print a
# {'test3': 3, 'test2': 0, 'test5': 4} 
print b
# OrderedDict([('test2', 0), ('test3', 3), ('test5', 4)])

Know that OrderedDict only keeps insertion order. It does not maintain some form of sorted order for new inserted key, values. The only order is that new key, values are guaranteed to be at the end of the dict.

dawg
  • 98,345
  • 23
  • 131
  • 206
0

The order of the keys in the dictionary are returned in no discernible order, as defined by Python itself. In your simple example, you're getting lucky.

So, I guess the short answer is that you're not allowed to store sorted dictionary keys.

Perhaps you could save off the sorted keys in a list separately, and use that to enumerate your dictionary.

CDahn
  • 1,795
  • 12
  • 23