Search code examples
pythonpython-3.xrecursionordereddict

Keeping the order of an OrderedDict


I have an OrderedDict that I'm passing to a function. Somewhere in the function it changes the ordering, though I'm not sure why and am trying to debug it. Here is an example of the function and the function and output:

def unnest_data(data):
    path_prefix = ''
    UNNESTED = OrderedDict()
    list_of_subdata = [(data, ''),] # (data, prefix)
    while list_of_subdata:
        for subdata, path_prefix in list_of_subdata:
            for key, value in subdata.items():
                path = (path_prefix + '.' + key).lstrip('.').replace('.[', '[')
                if not (isinstance(value, (list, dict))):
                    UNNESTED[path] = value
                elif isinstance(value, dict):
                    list_of_subdata.append((value, path))
                elif isinstance(value, list):
                    list_of_subdata.extend([(_, path) for _ in value])
            list_of_subdata.remove((subdata, path_prefix))
        if not list_of_subdata: break
    return UNNESTED

Then, if I call it:

from collections import OrderedDict
data = OrderedDict([('Item', OrderedDict([('[@ID]', '288917'), ('Main', OrderedDict([('Platform', 'iTunes'), ('PlatformID', '353736518')])), ('Genres', OrderedDict([('Genre', [OrderedDict([('[@FacebookID]', '6003161475030'), ('Value', 'Comedy')]), OrderedDict([('[@FacebookID]', '6003172932634'), ('Value', 'TV-Show')])])]))]))])
unnest_data(data)                  

I get an OrderedDict that doesn't match the ordering of my original one:

OrderedDict([('Item[@ID]', '288917'), ('Item.Genres.Genre[@FacebookID]', ['6003172932634', '6003161475030']), ('Item.Genres.Genre.Value', ['TV-Show', 'Comedy']), ('Item.Main.Platform', 'iTunes'), ('Item.Main.PlatformID', '353736518')])

Notice how it has "Genre" before "PlatformID", which is not the way it was sorted in the original dict. What seems to be my error here and how would I fix it?


Solution

  • It’s hard to say exactly what’s wrong without a complete working example. But based on the code you’ve shown, I suspect your problem isn’t with OrderedDict at all, but rather that you’re modifying list_of_subdata while iterating through it, which will result in items being unexpectedly skipped.

    >>> a = [1, 2, 3, 4, 5, 6, 7]
    >>> for x in a:
    ...     print(x)
    ...     a.remove(x)
    ... 
    1
    3
    5
    7
    

    Given your use, consider a deque instead of a list.