pythonjsondjangocomparison

How to compare two JSON objects with the same elements in a different order equal?


How can I test whether two JSON objects are equal in python, disregarding the order of lists?

For example ...

JSON document a:

{
    "errors": [
        {"error": "invalid", "field": "email"},
        {"error": "required", "field": "name"}
    ],
    "success": false
}

JSON document b:

{
    "success": false,
    "errors": [
        {"error": "required", "field": "name"},
        {"error": "invalid", "field": "email"}
    ]
}

a and b should compare equal, even though the order of the "errors" lists are different.


Solution

  • If you want two objects with the same elements but in a different order to compare equal, then the obvious thing to do is compare sorted copies of them - for instance, for the dictionaries represented by your JSON strings a and b:

    import json
    
    a = json.loads("""
    {
        "errors": [
            {"error": "invalid", "field": "email"},
            {"error": "required", "field": "name"}
        ],
        "success": false
    }
    """)
    
    b = json.loads("""
    {
        "success": false,
        "errors": [
            {"error": "required", "field": "name"},
            {"error": "invalid", "field": "email"}
        ]
    }
    """)
    
    >>> sorted(a.items()) == sorted(b.items())
    False
    

    ... but that doesn't work, because in each case, the "errors" item of the top-level dict is a list with the same elements in a different order, and sorted() doesn't try to sort anything except the "top" level of an iterable.

    To fix that, we can define an ordered function which will recursively sort any lists it finds (and convert dictionaries to lists of (key, value) pairs so that they're orderable):

    def ordered(obj):
        if isinstance(obj, dict):
            return sorted((k, ordered(v)) for k, v in obj.items())
        if isinstance(obj, list):
            return sorted(ordered(x) for x in obj)
        else:
            return obj
    

    If we apply this function to a and b, the results compare equal:

    >>> ordered(a) == ordered(b)
    True