Search code examples
pythonordereddict

Why do keys added to an OrderedDict and sorted inside of a function not stay sorted outside the function?


I have a function that contains code similar to the one below, which takes an OrdredDict object and a string as arguments:

def AddToOrderedDict(ordered_dict, new_key):
    ordered_dict[new_key] = []
    ordered_dict = OrderedDict(sorted(ordered_dict.items()))

This function will add the key to the dictionary and sort it, but not keep it sorted once it has left the function.

The code below demonstrates this behavior:

from collections import OrderedDict

def AddToOrderedDict(ordered_dict, new_key):
    ordered_dict[new_key] = ['New', 'List']
    ordered_dict = OrderedDict(sorted(ordered_dict.items()))
    print(dict(ordered_dict))

ordered_dict = OrderedDict()
ordered_dict['A'] = ['List', 'A']
ordered_dict['C'] = ['List', 'C']
ordered_dict['D'] = ['List', 'D']

AddToOrderedDict(ordered_dict, 'B')

print(dict(ordered_dict))

Output:

{'A': ['List', 'A'], 'B': ['New', 'List'], 'C': ['List', 'C'], 'D': ['List', 'D']}
{'A': ['List', 'A'], 'C': ['List', 'C'], 'D': ['List', 'D'], 'B': ['New', 'List']}

Why is the sorting not kept outside the function?


Solution

  • Variables in python are references to objects.

    When you pass the parameter you have two variables pointing to the same object, one inside the function and one outside.

    ordered_dict[new_key] = ["new","list"] modifies the existing OrderedDict object. So the change is visible outside the function.

    ordered_dict = OrderedDict(sorted(ordered_dict.items())) on the other hand creates a new OrderedDict and changes the ordered_dict variablein the function to reffer to it, it has no affect on the ordered_dict variable in the main program.

    If you can use external libraries you may want to look at the sortedcontainers module.


    Is there a way to act directly upon the passed variable

    Not a good one. There is a "move to end" function which could be used, but is likely to result in a bunch of unnessacery movement.

    I suspect that the least bad way to sort an OrderedDict in-place is to empty and refill it, something like.

    tmp = sorted(ordered_dict.items())
    ordered_dict.clear()
    ordered_dict.update(tmp)
    

    Ultimatley though, doing a full resort on every insert is likely a bad design. A proper sorted container is likely to perform much better if it's available.