How to sort a dict by value.
sorted() + a key function.
The most-asked Python dictionary question. The answer is always sorted(d.items(), key=...) — but the details matter. sorted() returns a list, not a dict. To sort by value, use item[1]. To sort by key, use item[0]. To go descending, use reverse=True. And since Python 3.7, you can convert back to a dict and keep the sorted order. This page covers each case, plus the itemgetter alternative.
Short answer: sorted(d.items(), key=lambda item: item[1]) — sorts by value, returns a list of (key, value) tuples. For descending: add reverse=True. To get a dict back: dict(sorted(d.items(), key=lambda item: item[1])) (Python 3.7+ preserves order). Sort by key: item[0]. For speed and readability, operator.itemgetter(1) replaces the lambda. Dicts don't have a .sort() method — always use sorted().
✅ The basic pattern
By value. By key. Ascending. Descending.
scores = {'Alice': 85, 'Bob': 72, 'Charlie': 95}
# Sort by value — ascending
by_value = sorted(scores.items(), key=lambda item: item[1])
print(by_value)
# [('Bob', 72), ('Alice', 85), ('Charlie', 95)]
# Sort by value — descending
by_value_desc = sorted(scores.items(), key=lambda item: item[1], reverse=True)
print(by_value_desc)
# [('Charlie', 95), ('Alice', 85), ('Bob', 72)]
# Sort by key
by_key = sorted(scores.items(), key=lambda item: item[0])
print(by_key)
# [('Alice', 85), ('Bob', 72), ('Charlie', 95)]
# Convert back to dict — preserves sorted order
by_value_dict = dict(sorted(scores.items(), key=lambda item: item[1]))
print(by_value_dict)
# {'Bob': 72, 'Alice': 85, 'Charlie': 95}
# Using itemgetter — faster, more readable
from operator import itemgetter
by_value = sorted(scores.items(), key=itemgetter(1))
print(by_value)
# [('Bob', 72), ('Alice', 85), ('Charlie', 95)]
by_key = sorted(scores.items(), key=itemgetter(0))
print(by_key)
# [('Alice', 85), ('Bob', 72), ('Charlie', 95)]
# Sort by multiple indices: value, then key
from operator import itemgetter
ties = sorted(scores.items(), key=itemgetter(1, 0))
Why item[1] for value:
d.items() yields tuples:
('Alice', 85)
('Bob', 72)
('Charlie', 95)
Index 0 is the key.
Index 1 is the value.
sorted(..., key=lambda item: item[1])
→ sorts by index 1 of each tuple
→ value-based sort
sorted(..., key=lambda item: item[0])
→ sorts by index 0
→ key-based sort
sorted(d.items())
→ default: compares tuples element by element
→ by key first, then by value for equal keys
→ equivalent to sort by key, then value
reverse=True
→ sorts descending
→ applies to whatever the key returns
→ works for strings, numbers, tuples
For dicts with mixed types:
sorted(d.items(), key=lambda x: str(x[0]))
→ converts key to string for comparison
→ rarely needed; usually dict keys are uniform
For case-insensitive key sort:
sorted(d.items(), key=lambda x: x[0].lower())
→ sort by lowercase key
→ useful for dictionaries with user names
For descending by value, ascending by key:
Can't do this with a single reverse.
Use a custom key:
sorted(d.items(), key=lambda x: (-x[1], x[0]))
→ negative value for descending
→ key for ascending tiebreaker
Only works for numeric values (can't negate strings).
For general mixed sorting:
use two passes with sort stability:
items = sorted(d.items(), key=lambda x: x[0]) # key asc
items = sorted(items, key=lambda x: x[1], reverse=True) # value desc
Stable sort preserves the first order for ties.
✅ Why you get a list
Dicts aren't sequences.
d = {'a': 1, 'b': 2, 'c': 3}
# sorted() on a dict — iterates keys
print(sorted(d)) # ['a', 'b', 'c']
# That's sorted keys, not a sorted dict.
# sorted() on .items() — returns list of tuples
print(sorted(d.items()))
# [('a', 1), ('b', 2), ('c', 3)]
# sorted() always returns a list, regardless of input.
print(type(sorted(d))) #
print(type(sorted(d.items()))) #
# To get a dict back, wrap it:
sorted_dict = dict(sorted(d.items(), key=lambda x: x[1], reverse=True))
print(sorted_dict) # {'c': 3, 'b': 2, 'a': 1}
print(type(sorted_dict)) #
# Since Python 3.7, the dict preserves insertion order.
# So the sorted order is the order of the new dict.
# Before Python 3.7 (rare today), you'd use OrderedDict:
from collections import OrderedDict
old_style = OrderedDict(sorted(d.items(), key=lambda x: x[1]))
# For modern Python, dict(sorted(...)) is enough.
# Sorting doesn't modify the original:
d_original = {'a': 3, 'b': 1, 'c': 2}
d_sorted = dict(sorted(d_original.items(), key=lambda x: x[1]))
print(d_original) # {'a': 3, 'b': 1, 'c': 2} — unchanged
print(d_sorted) # {'b': 1, 'c': 2, 'a': 3} — new dict
The reason sorted() returns a list:
sorted() works on any iterable.
For a dict, the natural iteration is over keys.
For d.items(), it's over tuples.
sorted() returns whatever type it produced —
and that's always a list.
The chain:
dict → iterable (via .items()) → sorted list
→ optionally back to dict
Or:
dict → list of (k, v) tuples → sorted list
→ optionally dict(...) to convert
The conversion step matters:
✅ sorted(d.items(), key=...) — a list of tuples
You can:
- Iterate it
- Slice it (top 5: sorted(...)[:5])
- Convert to dict: dict(sorted(...))
- Filter it with a comprehension
- Pass it to another function
✅ dict(sorted(...)) — a dict
You can:
- Look up by key (O(1))
- Iterate in insertion order (which is sorted)
- Convert back to a list
The list is more useful for intermediate steps.
The dict is more useful for lookups.
Real-world sorting patterns:
1. Top-N by value:
top_5 = sorted(d.items(), key=lambda x: x[1], reverse=True)[:5]
→ Keep it as a list. No need to convert back.
2. Full sorted dict:
d = dict(sorted(d.items(), key=lambda x: x[1]))
→ The dict preserves the order.
3. Convert to string for display:
for name, score in sorted(d.items(), key=lambda x: -x[1]):
print(f'{name}: {score}')
→ Iterate the sorted list directly.
4. Sort and keep the rest:
first, *rest = sorted(d.items(), key=lambda x: x[1])
→ Tuple unpacking on the sorted list.
The common mistake:
❌ d.sort(key=...) # AttributeError
Dicts don't have .sort().
❌ sorted(d, key=lambda x: x[1]) # IndexError
sorted(d) yields keys (strings), not tuples.
x[1] on a string is indexing.
✅ sorted(d.items(), key=lambda x: x[1])
Sort the (key, value) tuples.
✅ sorted(d.items())
Default sort by key, then value.
✅ Common patterns
The cases that come up in real code.
scores = {'Alice': 85, 'Bob': 72, 'Charlie': 95, 'Dave': 85}
# 1. Top N by value
top_2 = sorted(scores.items(), key=lambda x: x[1], reverse=True)[:2]
print(top_2)
# [('Charlie', 95), ('Alice', 85)]
# 2. Sort and keep as list (no dict conversion)
for name, score in sorted(scores.items(), key=lambda x: -x[1]):
print(f'{name}: {score}')
# 3. Sort by value, then by key for ties
sorted_by_value_then_key = sorted(
scores.items(),
key=lambda x: (-x[1], x[0]) # -value (descending), key (ascending)
)
print(sorted_by_value_then_key)
# [('Charlie', 95), ('Alice', 85), ('Dave', 85), ('Bob', 72)]
# 4. Sort by length of key
by_key_length = sorted(scores.items(), key=lambda x: len(x[0]))
print([k for k, _ in by_key_length])
# ['Bob', 'Dave', 'Alice', 'Charlie']
# 5. Sort by custom function
def score_category(score):
return 'high' if score >= 90 else 'medium' if score >= 80 else 'low'
by_category = sorted(scores.items(), key=lambda x: score_category(x[1]))
print(by_category)
# 6. Filter then sort
passing = sorted(
((k, v) for k, v in scores.items() if v >= 80),
key=lambda x: x[1],
reverse=True
)
print(passing)
# [('Charlie', 95), ('Alice', 85), ('Dave', 85)]
# 7. Sort keys only, then look up
sorted_keys = sorted(scores)
for key in sorted_keys:
print(key, scores[key])
Pattern 1: Top N
sorted(items, key=...)[:N]
→ slice the sorted list
→ no need to convert to dict
→ O(n log n) for the sort, then O(N) for the slice
→ for very large N, use heapq.nlargest (O(n log N))
Pattern 2: Iterate in order
for k, v in sorted(items, key=...):
...
→ most common
→ the list is temporary
→ no dict conversion needed
Pattern 3: Two-level sort
key=lambda x: (-x[1], x[0])
→ descending by value, ascending by key
→ works for numeric values (negation)
→ for strings or mixed, use two-pass stable sort
Pattern 4: Sort by custom property
key=lambda x: len(x[0]) # key length
key=lambda x: x[1].score # if value is an object
→ any function works as a key
→ return anything sortable
Pattern 5: Category sort
key=lambda x: category(x[1])
→ group by category
→ stable sort preserves order within category
→ sort by category, then by value for ties:
key=lambda x: (category(x[1]), x[1])
Pattern 6: Filter then sort
sorted((x for x in items if cond(x)), key=...)
→ filter first (fewer items to sort)
→ sort the filtered list
→ or sort then filter, but filter-first is faster
→ the generator expression avoids a temporary list
Pattern 7: Keys only
sorted(d) # sorted keys
→ works because iterating a dict yields keys
→ useful when you only need order, not values
The stable sort guarantee:
Python's sort is stable.
Equal elements preserve their relative order.
This is why two-pass sorting works:
sorted(d, key=lambda x: x[1]) # by value
sorted(d, key=lambda x: x[0]) # then by key
→ first pass by value, second pass by key
→ result: sorted by key, ties broken by value
→ equivalently: sorted(d, key=lambda x: (x[0], x[1]))
The tuple key is the idiomatic way to do
multi-level sorting. The two-pass is equivalent
but more verbose. Use the tuple key.
For simple sorts, use a lambda.
For complex sorts, use a named function.
For performance-critical sorts, use itemgetter.
The pattern you'll write most often:
dict(sorted(d.items(), key=lambda x: x[1], reverse=True))
→ sort by value descending
→ convert back to dict
→ the dict preserves the sorted order
→ iterate as many times as you want
Don't call .sort() on a dictionary. Dicts don't have a .sort() method — calling it raises AttributeError: 'dict' object has no attribute 'sort'. The only way to sort a dict is sorted(), which returns a list. To 'sort a dict in place', reassign: d = dict(sorted(d.items(), key=...)). The original dict is unchanged; a new sorted dict is created. If other code holds a reference to the old dict, it still sees the unsorted version. The correct pattern is to sort and rebind, or to sort and keep the result as a list if you don't need key lookups.
⚠️ Common mistakes
The dict-sorting mistakes that cost real time.
d.sort()AttributeError. Fix: sorted(d.items(), ...).
sorted(d, key=lambda x: x[1])IndexError — sorted(d) yields keys (strings). Fix: sorted(d.items(), ...).
sorted() to return a dictIt returns a list. Fix: wrap with dict(...).
reverse=True for numbers onlyWorks for strings too. Fix: reverse=True is general.
Confusing which index. Fix: item[0] = key, item[1] = value.
-x[1] fails for strings. Fix: reverse=True.
Old Python dicts were unordered. Fix: use OrderedDict or upgrade.
TypeError. Fix: key=lambda x: str(x[1]) or explicit comparison.
❓ Frequently asked
How do I sort a dictionary by value in Python?
Use sorted with a key function: sorted(d.items(), key=lambda item: item[1]). This returns a list of (key, value) tuples, sorted by value ascending. Pass reverse=True for descending. To convert back to a dict: dict(sorted(d.items(), key=lambda item: item[1])).
Why does sorted() return a list, not a dict?
Because dictionaries aren't sortable — they're mappings, not sequences. sorted() works on any iterable and returns a list. For dicts, the natural iterable is .items(). If you want a dict back, wrap it: dict(sorted(d.items(), key=...)). Since Python 3.7, dicts preserve insertion order.
How do I sort a dictionary by key?
Use item[0] as the key: sorted(d.items(), key=lambda item: item[0]). Or, more simply, use sorted(d) — since iterating a dict yields its keys, sorted(d) returns a list of sorted keys. Another way: sorted(d.items()) — the default sort compares tuples lexicographically, so it sorts by key first.
What is operator.itemgetter and when should I use it?
operator.itemgetter(i) returns a callable that extracts the i-th element from its argument. It's a faster, more readable alternative to a lambda in sorting. sorted(d.items(), key=operator.itemgetter(1)) is equivalent to sorted(d.items(), key=lambda x: x[1]) but slightly faster. For most code, the lambda is fine.
How do I sort a dict by value in descending order?
Pass reverse=True: sorted(d.items(), key=lambda item: item[1], reverse=True). Alternatively, negate numeric values: sorted(d.items(), key=lambda item: -item[1]). But this only works for numeric values. For strings, use reverse=True. The reverse parameter is the cleanest and most general.
Can I sort a dict in place?
No. Dictionaries don't have a sort method. sorted() always returns a new list. To 'sort a dict in place', reassign: d = dict(sorted(d.items(), key=...)). The original dict is replaced by a new one. If other code holds a reference to the old dict, it still sees the old unsorted version.
🔗 Continue learning
Next in this series:
enumerate, zip, and why range(len()) is an anti-pattern