
How to Sort a Dictionary by Value in Python
To sort a Python dictionary by its values, you leverage the sorted() function on the dictionary’s .items(), providing a lambda function as the key to specify sorting by the value element (index 1 of each item tuple). The result is a list of key-value tuples, which can then be reconstructed into a new ordered dictionary if needed.
my_dict = {'apple': 3, 'banana': 1, 'cherry': 2}
# Sort in ascending order by value
sorted_items_asc = sorted(my_dict.items(), key=lambda item: item[1])
# Result: [('banana', 1), ('cherry', 2), ('apple', 3)]
# Reconstruct into a dictionary (Python 3.7+ maintains insertion order)
sorted_dict_asc = dict(sorted_items_asc)
# Result: {'banana': 1, 'cherry': 2, 'apple': 3}
| Metric | Details |
|---|---|
| Time Complexity | O(N log N) for sorting, where N is the number of items. |
| Space Complexity | O(N) for the list of key-value tuples, plus O(N) if reconstructing a new dictionary. |
| Python Versions |
|
| Output Type | list of tuples (key, value) by default. Can be converted to a new dict. |
The Senior Dev Hook
When I first started tackling data structures in Python, I made the classic mistake of thinking a dictionary could be sorted in-place by value, like a list. That’s a fundamental misunderstanding of what a Python dictionary actually is. Dictionaries are inherently unordered (or insertion-ordered since Python 3.7), and you can’t “sort” the dictionary itself by its values without creating a new representation of that data. My early attempts often resulted in complex, unreadable loops or reliance on external modules when a simple, elegant one-liner with sorted() and a lambda was the correct, Pythonic approach all along. It taught me the importance of understanding the core properties of data structures before attempting to manipulate them.
Under the Hood Logic of Sorting by Value
To effectively sort a dictionary by its values, we first need to extract its key-value pairs into a format that can be sorted. This is where my_dict.items() comes in. This method returns a view object that displays a list of a dictionary’s key-value tuple pairs. For example, {'a': 1, 'b': 2}.items() would yield something like dict_items([('a', 1), ('b', 2)]).
The sorted() built-in function is the workhorse here. It takes an iterable (our list of tuples from .items()) and returns a new list containing all items from the iterable in ascending order. The magic happens with the key argument. By default, sorted() compares elements directly. However, we want to sort based on the *value* part of each (key, value) tuple, not the entire tuple or its key.
We achieve this by providing a lambda function, specifically lambda item: item[1]. For each tuple item in the list (e.g., ('apple', 3)), this lambda tells sorted() to extract the element at index 1 (which is the value, 3 in this case) and use that for comparison. The sorted() function then arranges these tuples based on these extracted values.
Crucially, the output of sorted() is always a list. If you need a dictionary back, especially one that preserves the sorted order, you must reconstruct it. In Python 3.7 and later, the standard dict() constructor guarantees that it maintains insertion order. This means if you pass it a list of key-value tuples that are already sorted, the resulting dictionary will reflect that order.
Step-by-Step Implementation
Let’s walk through the process with a concrete example, demonstrating both ascending and descending sorts.
1. Initializing Your Dictionary
First, we need a dictionary to work with. I’ll use a simple one for clarity.
# A dictionary representing product stock levels
stock_levels = {
'laptops': 15,
'monitors': 7,
'keyboards': 22,
'mice': 50,
'webcams': 8
}
print("Original Dictionary:", stock_levels)
Explanation: This creates our sample dictionary. Note that the order here is arbitrary from Python’s perspective (though 3.7+ will preserve insertion order).
2. Sorting in Ascending Order by Value
To sort from the smallest value to the largest, we use the basic sorted() call.
# Step 1: Get the items (key-value pairs) from the dictionary
# This returns a view object that behaves like a list of tuples: [('laptops', 15), ...]
dict_items_view = stock_levels.items()
# Step 2: Use sorted() with a lambda key to sort by the second element (value) of each tuple
# item[0] is the key, item[1] is the value
sorted_by_value_asc = sorted(dict_items_view, key=lambda item: item[1])
print("\nSorted by Value (Ascending - List of Tuples):", sorted_by_value_asc)
# Step 3 (Optional but common): Reconstruct into a new dictionary
# For Python 3.7+, dict() preserves insertion order.
sorted_dict_asc = dict(sorted_by_value_asc)
print("Sorted by Value (Ascending - Dictionary):", sorted_dict_asc)
Explanation:
stock_levels.items()gives us an iterable of(key, value)tuples.sorted(...)takes this iterable.key=lambda item: item[1]is the critical part. It tellssorted()to look at the second element (index 1) of eachitem(which is a(key, value)tuple) for comparison.- The result is a list of tuples, ordered by value.
dict(sorted_by_value_asc)converts this list of ordered tuples back into a dictionary, preserving the order because we’re on Python 3.7+.
3. Sorting in Descending Order by Value
To sort from the largest value to the smallest, we add the reverse=True argument to sorted().
# Sort in descending order by value using reverse=True
sorted_by_value_desc = sorted(stock_levels.items(), key=lambda item: item[1], reverse=True)
print("\nSorted by Value (Descending - List of Tuples):", sorted_by_value_desc)
# Reconstruct into a new dictionary
sorted_dict_desc = dict(sorted_by_value_desc)
print("Sorted by Value (Descending - Dictionary):", sorted_dict_desc)
Explanation:
- The only change here is
reverse=True, which inverts the sorting order.
What Can Go Wrong (Troubleshooting and Edge Cases)
Based on my experience, junior developers often run into a few specific issues when sorting dictionaries by value:
1. Misunderstanding the Output Type
The most common pitfall: assuming sorted(my_dict.items(), ...) magically transforms the original dictionary. It does not. The sorted() function *always* returns a new list. If you want a dictionary that *retains* this sort order, you must explicitly reconstruct it using dict() as shown above. Forgetting this leads to type errors or unexpected behavior when trying to access dictionary methods on what is now a list.
2. Python Version Incompatibility for Dictionary Order
This is a critical “Information Gain” point often missed. Before Python 3.7, standard dict objects did *not* guarantee insertion order. While iterating over .items() might have provided items in some consistent order for a given run, this was an implementation detail, not a language guarantee. If you are working with Python 3.6 or older, directly using dict(sorted_items) will likely result in an unordered dictionary. For those environments, you absolutely must use collections.OrderedDict to ensure order preservation:
from collections import OrderedDict
# For Python < 3.7:
my_dict = {'apple': 3, 'banana': 1, 'cherry': 2}
sorted_items = sorted(my_dict.items(), key=lambda item: item[1])
sorted_ordered_dict = OrderedDict(sorted_items) # Use OrderedDict explicitly
print("Sorted OrderedDict (for Python < 3.7):", sorted_ordered_dict)
Always verify your Python environment, especially in legacy systems. I've spent hours debugging systems that behaved differently in production due to a minor Python version mismatch.
3. Sorting by Multiple Criteria (Tie-breaking)
What happens if two values are identical? By default, Python's sorted() is stable, meaning it preserves the original relative order of equal elements. However, if you need explicit tie-breaking (e.g., if values are equal, sort by key), you can extend your lambda function:
data = {'a': 10, 'b': 20, 'c': 10, 'd': 5}
# Sort primarily by value (item[1]), secondarily by key (item[0])
sorted_data = sorted(data.items(), key=lambda item: (item[1], item[0]))
print("\nSorted by Value, then Key:", sorted_data)
# Output: [('d', 5), ('a', 10), ('c', 10), ('b', 20)]
Explanation: The `key` function now returns a tuple (item[1], item[0]). Python's tuple comparison rules mean it compares the first elements; if they're equal, it moves to the second elements, and so on.
4. Non-Comparable Values
If your dictionary values are complex objects (e.g., custom classes, lists, other dictionaries) that don't have a natural ordering or haven't implemented comparison methods (like __lt__), Python will raise a TypeError. Ensure that whatever you're trying to sort by is comparable.
Performance & Best Practices
When NOT to Use This Approach
While sorting by value is a common requirement, it's not always the most efficient or appropriate solution:
- Finding Min/Max Value: If your goal is simply to find the item with the minimum or maximum value, sorting the entire dictionary is overkill.
min(my_dict.items(), key=lambda item: item[1])ormax(my_dict.items(), key=lambda item: item[1])can achieve this in O(N) time, which is faster than the O(N log N) of a full sort. - Frequent Sorting of Static Data: If your dictionary is sorted frequently but rarely changes, consider maintaining a separate sorted list of keys or values, or using a data structure like a min-heap (
heapq) if you only need the smallest K elements. Re-sorting the entire dictionary every time is inefficient. - Memory Constraints on Large Dictionaries: Sorting by value creates a new list of all key-value tuples, and then potentially a new dictionary. For extremely large dictionaries, this O(N) space complexity might be prohibitive. Consider streaming or custom iterators if memory is a major concern.
Alternative Methods and Benchmarking
While `lambda` is highly readable and idiomatic Python, you can also use `operator.itemgetter` for potentially minor performance gains and slightly different readability, especially in scenarios where you're repeatedly sorting.
import operator
import timeit
my_dict = {f'key_{i}': i % 100 for i in range(10000)} # Large dictionary for benchmark
# Using lambda
time_lambda = timeit.timeit("sorted(my_dict.items(), key=lambda item: item[1])", globals={'my_dict': my_dict}, number=100)
print(f"Time with lambda: {time_lambda:.6f} seconds")
# Using operator.itemgetter
time_itemgetter = timeit.timeit("sorted(my_dict.items(), key=operator.itemgetter(1))", globals={'my_dict': my_dict, 'operator': operator}, number=100)
print(f"Time with operator.itemgetter: {time_itemgetter:.6f} seconds")
Benchmarking Insights: In most practical scenarios, the performance difference between lambda item: item[1] and operator.itemgetter(1) is negligible. itemgetter might offer a marginal speedup for very large datasets due to being implemented in C, but for readability and common use cases, the lambda is perfectly acceptable. I generally recommend starting with lambda for junior developers due to its explicit nature and only optimizing to itemgetter if profiling points to the sort key as a bottleneck.
For more on this, Check out more Python Basics Tutorials.
Author's Final Verdict
In my professional experience, sorting a dictionary by value using sorted(my_dict.items(), key=lambda item: item[1]) is the go-to method for its clarity, conciseness, and "Pythonic" elegance. It's a fundamental pattern every Python developer should master. The key takeaways are to always remember that the direct output is a list of tuples, and to be mindful of your Python version when reconstructing an ordered dictionary. For Python 3.7+, the standard dict() constructor will serve you well. For older versions, explicitly reaching for collections.OrderedDict is crucial. Don't over-optimize prematurely; the lambda approach is robust and performant enough for the vast majority of real-world applications.
Have any thoughts?
Share your reaction or leave a quick response — we’d love to hear what you think!