Python - Sort Dictionary by Key or Value
Sorting a dictionary by its keys is straightforward using the `sorted()` function combined with `dict()` constructor or dictionary comprehension.
Key Insights
- Python dictionaries maintain insertion order since Python 3.7, but sorting creates new ordered structures using
sorted(),dict(), and operator functions - Sort by keys using
sorted(dict.items())or by values withkey=lambdaoroperator.itemgetter()for better performance - Reverse sorting, custom comparisons, and nested dictionary sorting require specific techniques but follow the same fundamental patterns
Basic Dictionary Sorting by Key
Sorting a dictionary by its keys is straightforward using the sorted() function combined with dict() constructor or dictionary comprehension.
# Original dictionary
prices = {'banana': 2.50, 'apple': 1.20, 'orange': 3.00, 'grape': 4.50}
# Method 1: Using dict() and sorted()
sorted_prices = dict(sorted(prices.items()))
print(sorted_prices)
# Output: {'apple': 1.2, 'banana': 2.5, 'grape': 4.5, 'orange': 3.0}
# Method 2: Dictionary comprehension
sorted_prices = {k: prices[k] for k in sorted(prices)}
print(sorted_prices)
# Output: {'apple': 1.2, 'banana': 2.5, 'grape': 4.5, 'orange': 3.0}
The items() method returns key-value pairs as tuples, and sorted() naturally sorts tuples by their first element (the key). For reverse order:
# Reverse alphabetical order
reverse_sorted = dict(sorted(prices.items(), reverse=True))
print(reverse_sorted)
# Output: {'orange': 3.0, 'grape': 4.5, 'banana': 2.5, 'apple': 1.2}
Sorting Dictionary by Value
Sorting by values requires specifying a custom key function. The lambda function or operator.itemgetter() extracts the value from each key-value tuple.
from operator import itemgetter
inventory = {'laptop': 5, 'mouse': 45, 'keyboard': 12, 'monitor': 8}
# Method 1: Lambda function
sorted_by_value = dict(sorted(inventory.items(), key=lambda item: item[1]))
print(sorted_by_value)
# Output: {'laptop': 5, 'monitor': 8, 'keyboard': 12, 'mouse': 45}
# Method 2: operator.itemgetter (more efficient)
sorted_by_value = dict(sorted(inventory.items(), key=itemgetter(1)))
print(sorted_by_value)
# Output: {'laptop': 5, 'monitor': 8, 'keyboard': 12, 'mouse': 45}
# Reverse order (highest to lowest)
sorted_desc = dict(sorted(inventory.items(), key=itemgetter(1), reverse=True))
print(sorted_desc)
# Output: {'mouse': 45, 'keyboard': 12, 'monitor': 8, 'laptop': 5}
The operator.itemgetter(1) approach is faster than lambda for simple value extraction, especially with large dictionaries.
Sorting with Multiple Criteria
When values are identical, you can sort by secondary criteria using tuple comparisons in the key function.
# Dictionary with duplicate values
scores = {'Alice': 85, 'Bob': 92, 'Charlie': 85, 'Diana': 92, 'Eve': 78}
# Sort by score (descending), then by name (ascending)
sorted_scores = dict(sorted(scores.items(), key=lambda x: (-x[1], x[0])))
print(sorted_scores)
# Output: {'Bob': 92, 'Diana': 92, 'Alice': 85, 'Charlie': 85, 'Eve': 78}
The negative sign before x[1] reverses the numeric sort while keeping the name sort ascending.
Sorting Nested Dictionaries
Nested dictionaries require accessing the specific nested value in the key function.
employees = {
'E001': {'name': 'John', 'salary': 75000, 'department': 'IT'},
'E002': {'name': 'Sarah', 'salary': 82000, 'department': 'HR'},
'E003': {'name': 'Mike', 'salary': 68000, 'department': 'IT'},
'E004': {'name': 'Emma', 'salary': 82000, 'department': 'Finance'}
}
# Sort by salary (descending)
by_salary = dict(sorted(employees.items(), key=lambda x: x[1]['salary'], reverse=True))
for emp_id, details in by_salary.items():
print(f"{emp_id}: {details['name']} - ${details['salary']}")
# Output:
# E002: Sarah - $82000
# E004: Emma - $82000
# E001: John - $75000
# E003: Mike - $68000
# Sort by department, then salary
by_dept_salary = dict(sorted(employees.items(),
key=lambda x: (x[1]['department'], -x[1]['salary'])))
for emp_id, details in by_dept_salary.items():
print(f"{emp_id}: {details['department']} - {details['name']}")
# Output:
# E004: Finance - Emma
# E002: HR - Sarah
# E001: IT - John
# E003: IT - Mike
Custom Sorting Logic
Implement complex sorting rules using custom functions instead of lambda expressions for better readability.
products = {
'PRD001': {'name': 'Widget', 'price': 25.99, 'stock': 0},
'PRD002': {'name': 'Gadget', 'price': 45.50, 'stock': 15},
'PRD003': {'name': 'Tool', 'price': 12.75, 'stock': 0},
'PRD004': {'name': 'Device', 'price': 89.99, 'stock': 5}
}
def product_priority(item):
"""Sort by: in-stock first, then by price descending"""
product_id, details = item
in_stock = 1 if details['stock'] > 0 else 0
return (-in_stock, -details['price'])
sorted_products = dict(sorted(products.items(), key=product_priority))
for prod_id, details in sorted_products.items():
print(f"{details['name']}: ${details['price']} (Stock: {details['stock']})")
# Output:
# Device: $89.99 (Stock: 5)
# Gadget: $45.5 (Stock: 15)
# Widget: $25.99 (Stock: 0)
# Tool: $12.75 (Stock: 0)
Performance Considerations
For large dictionaries, choose the most efficient sorting method based on your needs.
import timeit
from operator import itemgetter
# Create large dictionary
large_dict = {f'key_{i}': i for i in range(10000)}
# Benchmark different methods
def sort_lambda():
return dict(sorted(large_dict.items(), key=lambda x: x[1]))
def sort_itemgetter():
return dict(sorted(large_dict.items(), key=itemgetter(1)))
lambda_time = timeit.timeit(sort_lambda, number=1000)
itemgetter_time = timeit.timeit(sort_itemgetter, number=1000)
print(f"Lambda: {lambda_time:.4f} seconds")
print(f"Itemgetter: {itemgetter_time:.4f} seconds")
# itemgetter is typically 15-20% faster
Sorting Dictionary Keys or Values Only
Sometimes you only need sorted keys or values without creating a new dictionary.
data = {'z': 100, 'a': 200, 'm': 150}
# Get sorted keys only
sorted_keys = sorted(data.keys())
print(sorted_keys) # Output: ['a', 'm', 'z']
# Get sorted values only
sorted_values = sorted(data.values())
print(sorted_values) # Output: [100, 150, 200]
# Get keys sorted by their values
keys_by_value = sorted(data, key=data.get)
print(keys_by_value) # Output: ['z', 'm', 'a']
# Access in sorted order without creating new dict
for key in sorted(data, key=data.get, reverse=True):
print(f"{key}: {data[key]}")
# Output:
# a: 200
# m: 150
# z: 100
Maintaining Sort Order with OrderedDict
While modern Python dictionaries maintain insertion order, OrderedDict provides additional methods for reordering.
from collections import OrderedDict
# Regular dict sorting
regular = {'c': 3, 'a': 1, 'b': 2}
sorted_regular = dict(sorted(regular.items()))
# OrderedDict with move_to_end
ordered = OrderedDict([('c', 3), ('a', 1), ('b', 2)])
ordered.move_to_end('a') # Move 'a' to end
print(ordered) # Output: OrderedDict([('c', 3), ('b', 2), ('a', 1)])
ordered.move_to_end('c', last=False) # Move 'c' to beginning
print(ordered) # Output: OrderedDict([('c', 3), ('b', 2), ('a', 1)])
Dictionary sorting in Python is a fundamental operation that combines built-in functions with functional programming concepts. Choose sorted() with appropriate key functions for most cases, use operator.itemgetter() for performance-critical code, and implement custom sort functions for complex business logic. Understanding these patterns enables efficient data manipulation in any Python application.