Sort nested dicts in Python


by Antoine - categories : Programming Python

In this post, we will see how to sort one to many-levels-nested dictionnaries in CPython version >= 3.7 with the sorted() function. Starting with a simple 1-level dict, to 4-levels nested dict.

One level

I want to sort the following dict by the integer value. This is the simplest case, a dict with only one level.

dico = {
    "l1_key1": 2,
    "l1_key2": 1,
    "l1_key3": 3
}

Solution

We call sorted() with two arguments : what to move/sort, and the sorting key.

sorted(dico.items(), key=lambda x: x[1])

Details

What to sort/move :

dico.items()

What is the sorting key :

key=lambda x: x[1]

One more thing. Sorted will always return a list with keys as strings, and tuples as values. Just cast it to dict. The dict is our new-sorted dico, so just update it.

sorted_dico = dict(sorted(dico.items(), key=lambda x:x[1]))
dico = sorted_dico
print(dico)
{
    'l1_key2': 1,
    'l1_key1': 2,
    'l1_key3': 3
}

Two levels

I want to sort the following dict on Level1 keys, by the value of Level2 keys2. Scroll down to the end of this post to catch a glimpse at the wanted output

dico = {
    "l1_k1": {
        "l2_k1": "blabla",
        "l2_k2": 1
    },

    "l1_k2": {
        "l2_k1": "blabla",
        "l2_k2": 2
    },

    "l1_k3": {
        "l2_k1": "blabla",
        "l2_k2": 3
    }
}

Solution

sorted(dico.items(), key=lambda x: x[1]['l2_k2'])

Details

What to sort/move :

dico.items()

What is the sorting key :

key=lambda x: x[1]['l2_k2']
sorted_dico = dict(sorted(dico.items(),
                          key=lambda x:x[1]['l2_k2']))
dico = sorted_dico
print(dico)

Output :

{
    'l1_k3': {
        'l2_k1': "blabla",
        'l2_k2': 1
    },

    'l1_k1': {
        'l2_k1': "blabla",
        'l2_k2': 2
    },

    'l1_k2': {
        'l2_k1': "blabla",
        'l2_k2': 3
    }
}

Sort 2nd-level key by 4th-level value

A bit harder this time. I want to sort the following dict on Level2 keys, by the value of Level4 keys. If it's not clear in your mind, scroll down to the end to catch a glimpse at the wanted output.

dico = {
    "l1_k1": {
        "l2_k1": {
            "l3_k1": "blabla",
            "l3_k2": {
                "l4_k1": "blabla",
                "l4_k2": 3
            }
        },

        "l2_k2": {
            "l3_k1": "blabla",
            "l3_k2": {
                "l4_k1": "blabla",
                "l4_k2": 1
            }
        },

        "l2_k3": {
            "l3_k1": "blabla",
            "l3_k2": {
                "l4_k1": "blabla",
                "l4_k2": 2
            }
        }
    },
    "l1_k2": {"a key": "blabla"},
    "l1_k3": {"a key": "blabla"}
}

Solution

sorted(dico['l1_k1'].items(),
       key=lambda x: x[1]['l3_k2']['l4_k2']))

Details

What to sort/move :

dico['l1_k1'].items()

What is the sorting key :

key=lambda x: x[1]['l3_k2']['l4_k2']
sorted_dico_l2 = dict(sorted(dico['l1_key'].items(),
                             key=lambda x: x[1]['l3_key2']['l4_key2']))
dico['l1_key'] = sorted_dico_l2
print(dico)

Output :

{
    "l1_k1": {
        "l2_k2": {
            "l3_k1": "blabla",
            "l3_k2": {
                "l4_k1": "blabla",
                "l4_k2": 1
            }
        },

        "l2_k3": {
            "l3_k1": "blabla",
            "l3_k2": {
                "l4_k1": "blabla",
                "l4_k2": 2
            }
        },

        "l2_k1": {
            "l3_k1": "blabla",
            "l3_k2": {
                "l4_k1": "blabla",
                "l4_k2": 3
            }
        }
    },

    "l1_k2": {"a key": "blabla"},
    "l1_k3": {"a key": "blabla"}
}

More complex sorting key

A sorting function can be used as a key to return a more complex sorting. Let's say we want to sort some articles by creation date (cr_date), then by update date (up_date).

sorted(dico['l1_k1'].items(),
       key=sorter)


    def sorter(x):
        cr_date = x[1]['cr_date']
        up_date = x[1]['up_date']

        return (cr_date, up_date)

Reverse sorting order

The .sorted() function takes another useful optional argument called reverse. Setting reverse=True, well, reverse the sorting order. It is set by default to False.


Be the first to comment 🡮

5