Skip to main content

How to Compare JSON Objects Regardless of Order in Python

JSON (JavaScript Object Notation) is the most widely used data interchange format in modern web applications and APIs. When working with JSON data in Python, you'll frequently need to compare two JSON objects to check if they contain the same data, even when the keys or array elements appear in a different order.

This is a common challenge because JSON object properties have no guaranteed order, and two API responses with identical data might serialize keys differently. In this guide, you'll learn multiple reliable methods to compare JSON objects regardless of order in Python, handling everything from simple flat structures to deeply nested objects.

The Problem: Order Shouldn't Matter

Consider two JSON strings that represent the same data but with different key ordering:

import json

json_1 = '{"name": "Alice", "age": 30, "city": "London"}'
json_2 = '{"city": "London", "name": "Alice", "age": 30}'

A simple string comparison would fail even though the data is identical:

print(json_1 == json_2)

Output:

False

The strings are different, but the data they represent is the same. We need smarter comparison methods.

Comparing Simple JSON Objects Directly

For flat JSON objects (no nested structures or arrays), you can parse them into Python dictionaries and compare directly. Python dictionaries compare by content, not by insertion order.

import json

json_1 = '{"name": "Alice", "age": 30, "city": "London"}'
json_2 = '{"city": "London", "name": "Alice", "age": 30}'

dict_1 = json.loads(json_1)
dict_2 = json.loads(json_2)

print(dict_1 == dict_2)

Output:

True
tip

Python dictionaries compare equal if they have the same keys and values, regardless of insertion order. For flat JSON objects without arrays, direct == comparison is all you need.

Using sorted() for Top-Level Comparison

You can also sort dictionary items and compare them. This approach makes the comparison explicit:

import json

json_1 = '{"name": "Alice", "age": 30, "city": "London"}'
json_2 = '{"city": "London", "name": "Alice", "age": 30}'

dict_1 = json.loads(json_1)
dict_2 = json.loads(json_2)

print(sorted(dict_1.items()) == sorted(dict_2.items()))

Output:

True
Limitation: sorted() Doesn't Handle Nested Structures

The sorted() approach only works at the top level of the dictionary. If your JSON contains nested arrays or objects, sorted() won't sort them recursively:

import json

json_1 = '{"name": "Alice", "skills": ["Python", "Java", "SQL"]}'
json_2 = '{"name": "Alice", "skills": ["SQL", "Python", "Java"]}'

dict_1 = json.loads(json_1)
dict_2 = json.loads(json_2)

print(sorted(dict_1.items()) == sorted(dict_2.items()))

Output:

False

The data is semantically the same, but the arrays have different element orders. The next section solves this problem.

For robust comparison of complex JSON objects, including nested dictionaries and arrays in any order, use a recursive sorting function that normalizes the entire structure before comparing.

import json

def normalize(obj):
"""Recursively sort dictionaries and lists for order-independent comparison."""
if isinstance(obj, dict):
return sorted((k, normalize(v)) for k, v in obj.items())
if isinstance(obj, list):
return sorted(normalize(item) for item in obj)
return obj


json_1 = '{"name": "Alice", "skills": ["Python", "Java", "SQL"], "address": {"city": "London", "country": "UK"}}'
json_2 = '{"address": {"country": "UK", "city": "London"}, "skills": ["SQL", "Python", "Java"], "name": "Alice"}'

dict_1 = json.loads(json_1)
dict_2 = json.loads(json_2)

print(normalize(dict_1) == normalize(dict_2))

Output:

True

How it works:

  1. Dictionaries are converted into sorted lists of (key, value) tuples, ensuring key order doesn't affect comparison.
  2. Lists are sorted so element order doesn't matter.
  3. Primitive values (strings, numbers, booleans, None) are returned as-is.
  4. The function calls itself recursively, handling any depth of nesting.

Testing with Complex Nested JSON

import json

def normalize(obj):
"""Recursively sort dictionaries and lists for order-independent comparison."""
if isinstance(obj, dict):
return sorted((k, normalize(v)) for k, v in obj.items())
if isinstance(obj, list):
return sorted(normalize(item) for item in obj)
return obj

json_1 = '''
{
"company": "TechCorp",
"employees": [
{"name": "Bob", "skills": ["Java", "Python"]},
{"name": "Alice", "skills": ["SQL", "Python"]}
],
"locations": ["London", "New York", "Tokyo"]
}
'''

json_2 = '''
{
"locations": ["Tokyo", "London", "New York"],
"company": "TechCorp",
"employees": [
{"skills": ["Python", "SQL"], "name": "Alice"},
{"skills": ["Python", "Java"], "name": "Bob"}
]
}
'''

dict_1 = json.loads(json_1)
dict_2 = json.loads(json_2)

print(f"Direct comparison: {dict_1 == dict_2}")
print(f"Normalized comparison: {normalize(dict_1) == normalize(dict_2)}")

Output:

Direct comparison:    False
Normalized comparison: True
Important: When List Order Matters

The normalize() function sorts all lists, which means it treats list order as irrelevant. If the order of array elements is meaningful in your use case (e.g., a sequence of steps), you should not sort lists. Modify the function to sort only when appropriate:

def normalize_keep_list_order(obj):
"""Sort dictionaries but preserve list order."""
if isinstance(obj, dict):
return sorted((k, normalize_keep_list_order(v)) for k, v in obj.items())
if isinstance(obj, list):
return [normalize_keep_list_order(item) for item in obj] # No sorting
return obj

Using json.dumps() with sort_keys

A simpler alternative for many cases is to serialize both objects to JSON strings with sort_keys=True, then compare the strings:

import json

json_1 = '{"name": "Alice", "age": 30, "city": "London"}'
json_2 = '{"city": "London", "name": "Alice", "age": 30}'

dict_1 = json.loads(json_1)
dict_2 = json.loads(json_2)

normalized_1 = json.dumps(dict_1, sort_keys=True)
normalized_2 = json.dumps(dict_2, sort_keys=True)

print(normalized_1 == normalized_2)
print(normalized_1)

Output:

True
{"age": 30, "city": "London", "name": "Alice"}

This approach sorts dictionary keys at all nesting levels but does not sort array elements, which may be exactly what you want if list order is significant.

import json

# Nested example
dict_1 = {"b": 2, "a": {"d": 4, "c": 3}}
dict_2 = {"a": {"c": 3, "d": 4}, "b": 2}

print(json.dumps(dict_1, sort_keys=True) == json.dumps(dict_2, sort_keys=True))

Output:

True

Using deepdiff for Detailed Comparison

For production applications where you need to know what's different (not just whether objects are equal), the third-party deepdiff library provides comprehensive comparison with detailed reports.

pip install deepdiff
from deepdiff import DeepDiff

dict_1 = {
"name": "Alice",
"age": 30,
"skills": ["Python", "Java"]
}

dict_2 = {
"name": "Alice",
"age": 31,
"skills": ["Java", "Python", "SQL"]
}

# ignore_order=True makes comparison order-independent
diff = DeepDiff(dict_1, dict_2, ignore_order=True)

if diff:
print("Differences found:")
for diff_type, details in diff.items():
print(f" {diff_type}: {details}")
else:
print("Objects are identical.")

Output:

Differences found:
values_changed: {"root['age']": {'new_value': 31, 'old_value': 30}}
iterable_item_added: {"root['skills'][2]": 'SQL'}
note

deepdiff tells you exactly what changed, where it changed, and what the old and new values are, invaluable for debugging and testing.

Building a Reusable Comparison Function

Here's a complete, reusable function that handles various comparison scenarios:

import json

def compare_json(json_1, json_2, ignore_list_order=True):
"""
Compare two JSON objects for equality regardless of key order.

Args:
json_1: JSON string or Python dict/list.
json_2: JSON string or Python dict/list.
ignore_list_order: If True, list element order is ignored.

Returns:
True if objects are equal, False otherwise.
"""
# Parse strings if necessary
if isinstance(json_1, str):
json_1 = json.loads(json_1)
if isinstance(json_2, str):
json_2 = json.loads(json_2)

def normalize(obj):
if isinstance(obj, dict):
return sorted((k, normalize(v)) for k, v in obj.items())
if isinstance(obj, list):
if ignore_list_order:
return sorted(normalize(item) for item in obj)
return [normalize(item) for item in obj]
return obj

return normalize(json_1) == normalize(json_2)


# Test cases
print(compare_json('{"a": 1, "b": 2}', '{"b": 2, "a": 1}'))
print(compare_json('{"x": [3, 1, 2]}', '{"x": [1, 2, 3]}'))
print(compare_json('{"x": [3, 1, 2]}', '{"x": [1, 2, 3]}', ignore_list_order=False))

Output:

True
True
False

Quick Comparison of Methods

MethodHandles Nested DictsHandles List OrderShows DifferencesExternal Dependency
Direct == comparison❌ (order matters)None
sorted() on items❌ (top-level only)None
Recursive normalize()✅ (configurable)None
json.dumps(sort_keys=True)✅ (keys only)❌ (order matters)None
deepdiffdeepdiff

Conclusion

Comparing JSON objects regardless of order in Python requires different approaches depending on the complexity of your data:

  • For flat JSON objects, direct dictionary comparison (dict_1 == dict_2) works out of the box since Python dicts are order-independent.
  • For nested objects with ordered lists, use json.dumps(sort_keys=True) to normalize key order at all levels.
  • For full order-independent comparison (including arrays), use a recursive normalization function that sorts both dictionaries and lists before comparing.
  • For detailed difference reports, use the deepdiff library with ignore_order=True to see exactly what differs between two JSON objects.

The recursive normalize() approach is the most versatile pure-Python solution and handles the vast majority of real-world comparison scenarios.