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
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
sorted() Doesn't Handle Nested StructuresThe 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.
Recursive 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:
True
How 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: True
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'}
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
| 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.