Python · Syntax · Intermediate
Sorting and custom comparators
sorted() and list.sort() with key= functions, reverse, and multi-key comparators.
Quick topic start and explanations before exercises (exercises below):
Tuple keys, operator.itemgetter, and multi-field sorting
#heapq, cmp_to_key, and Timsort internals
#Exercises:
Sort by absolute value
#Write a function that takes a list of integers and returns them sorted by their absolute value, ascending.
def sort_by_abs(numbers):
pass
print(sort_by_abs([-5, 3, -1, 4, -2, 8]))
Solution
def sort_by_abs(numbers):
return sorted(numbers, key=abs)
print(sort_by_abs([-5, 3, -1, 4, -2, 8]))
Sort strings case-insensitively
#Write a function that takes a list of strings and returns them sorted alphabetically, ignoring case.
def sort_words(words):
pass
print(sort_words(["Banana", "apple", "Cherry", "date"]))
Solution
def sort_words(words):
return sorted(words, key=str.lower)
print(sort_words(["Banana", "apple", "Cherry", "date"]))
Sort by last name
#Write a function that takes a list of full names (strings like 'First Last') and returns them sorted alphabetically by last name.
def sort_by_last_name(names):
pass
names = ["Alice Smith", "Bob Johnson", "Carol Adams", "Dave Brown"]
print(sort_by_last_name(names))
Solution
def sort_by_last_name(names):
return sorted(names, key=lambda name: name.split()[-1])
names = ["Alice Smith", "Bob Johnson", "Carol Adams", "Dave Brown"]
print(sort_by_last_name(names))
Sort dictionaries by multiple fields
#Write a function that takes a list of product dictionaries (each with 'category' and 'price' keys) and returns them sorted first by category (A-Z), then by price (ascending) within each category.
def sort_products(products):
pass
products = [
{"name": "Bread", "category": "food", "price": 2},
{"name": "TV", "category": "electronics", "price": 500},
{"name": "Milk", "category": "food", "price": 1},
{"name": "Phone", "category": "electronics", "price": 800},
]
for p in sort_products(products):
print(p)
Solution
def sort_products(products):
return sorted(products, key=lambda p: (p["category"], p["price"]))
products = [
{"name": "Bread", "category": "food", "price": 2},
{"name": "TV", "category": "electronics", "price": 500},
{"name": "Milk", "category": "food", "price": 1},
{"name": "Phone", "category": "electronics", "price": 800},
]
for p in sort_products(products):
print(p)
Sort in-place vs return new
#Write two functions: one that sorts a list of numbers in-place (modifying the original) and returns None, and one that returns a sorted copy without modifying the original.
def sort_inplace(numbers):
pass
def sort_copy(numbers):
pass
nums = [3, 1, 4, 1, 5]
sort_inplace(nums)
print(nums)
nums2 = [3, 1, 4, 1, 5]
result = sort_copy(nums2)
print(nums2)
print(result)
Solution
def sort_inplace(numbers):
numbers.sort()
def sort_copy(numbers):
return sorted(numbers)
nums = [3, 1, 4, 1, 5]
sort_inplace(nums)
print(nums)
nums2 = [3, 1, 4, 1, 5]
result = sort_copy(nums2)
print(nums2)
print(result)
Top N
#Write a function that takes a list of numbers and an integer n, and returns the n largest numbers in descending order.
def top_n(numbers, n):
pass
print(top_n([3, 1, 4, 1, 5, 9, 2, 6, 5, 3], 3))
Solution
def top_n(numbers, n):
return sorted(numbers, reverse=True)[:n]
# Or more efficient for large lists:
def top_n(numbers, n):
import heapq
return heapq.nlargest(n, numbers)
print(top_n([3, 1, 4, 1, 5, 9, 2, 6, 5, 3], 3))
Sort by frequency
#Write a function that takes a list of numbers and returns them sorted by how often they appear — most frequent first. Elements with the same frequency should remain in their original relative order.
def sort_by_frequency(numbers):
pass
print(sort_by_frequency([4, 2, 2, 8, 3, 3, 1, 3]))
Solution
def sort_by_frequency(numbers):
from collections import Counter
freq = Counter(numbers)
return sorted(numbers, key=lambda n: -freq[n])
print(sort_by_frequency([4, 2, 2, 8, 3, 3, 1, 3]))
Stable sort property
#Write a function that takes a list of (name, score) tuples and returns them sorted by score descending. When scores are equal, preserve the original order of names (stable sort).
def rank_players(players):
pass
players = [("Alice", 90), ("Bob", 85), ("Carol", 90), ("Dave", 85)]
print(rank_players(players))
Solution
def rank_players(players):
return sorted(players, key=lambda p: -p[1])
players = [("Alice", 90), ("Bob", 85), ("Carol", 90), ("Dave", 85)]
print(rank_players(players))
Sort with mixed ascending/descending
#Write a function that takes a list of (name, age) tuples and returns them sorted by name ascending and age descending when names are equal.
def sort_people(people):
pass
people = [("Alice", 30), ("Bob", 25), ("Alice", 25), ("Bob", 35)]
print(sort_people(people))
Solution
def sort_people(people):
return sorted(people, key=lambda p: (p[0], -p[1]))
people = [("Alice", 30), ("Bob", 25), ("Alice", 25), ("Bob", 35)]
print(sort_people(people))
Custom sort with functools.cmp_to_key
#Write a function that sorts a list of version strings (like '1.10.2', '1.9.0') correctly as version numbers, not as plain strings. Use functools.cmp_to_key.
from functools import cmp_to_key
def sort_versions(versions):
pass
print(sort_versions(["1.10.2", "1.9.0", "2.0.0", "1.9.10", "1.1.0"]))
Solution
from functools import cmp_to_key
def sort_versions(versions):
def compare(a, b):
a_parts = list(map(int, a.split(".")))
b_parts = list(map(int, b.split(".")))
if a_parts < b_parts: return -1
if a_parts > b_parts: return 1
return 0
return sorted(versions, key=cmp_to_key(compare))
print(sort_versions(["1.10.2", "1.9.0", "2.0.0", "1.9.10", "1.1.0"]))