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:
FalseThe 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:
TrueUsing 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:
TrueRecursive Deep Comparison (Recommended)
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:
TrueHow it works:
- Dictionaries are converted into sorted lists of
(key, value)tuples, ensuring key order doesn't affect comparison. - Lists are sorted so element order doesn't matter.
- Primitive values (strings, numbers, booleans,
None) are returned as-is. - 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: TrueUsing 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
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:
TrueUsing 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 deepdifffrom deepdiff import DeepDiff
dict_1 = {
"name": "Alice",
"age": 30,
"skills": ["Python", "Java"]
}
dict_2 = {
"name": "Alice",
"age": 31,
"skills": ["Java", "Python", "SQL"]
}
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'}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.
"""
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)
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
FalseQuick Comparison of Methods
| Method | Handles Nested Dicts | Handles List Order | Shows Differences | External 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 |
deepdiff |
✅ | ✅ | ✅ | deepdiff |
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
deepdifflibrary withignore_order=Trueto 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.