PYTHON • ALGORITHMS AND COMPLEXITY

sorted() with Key Functions — Use sorted() with key and reverse parameters

Master Python's sorted() function to arrange any data by custom rules using key functions and reverse ordering.

Historical Context & Motivation

Sorting is one of the oldest and most studied problems in computer science. From the earliest days of computing, programmers needed ways to arrange data in a meaningful order — alphabetizing names, ranking scores, or organizing files by date. Early sorting required writing dozens of lines of code, and customizing the sort order was even harder.

Python's sorted() function was designed to make sorting simple, readable, and powerful. It builds on decades of algorithm research — particularly the development of Timsort, a hybrid sorting algorithm created by Tim Peters specifically for Python. The key parameter was introduced to let programmers define custom sorting rules without rewriting the sort itself.

1945
First Sorting Programs
John von Neumann writes one of the first recorded sorting programs for the EDVAC computer, establishing sorting as a fundamental computing task.
1991
Python 1.0 Released
Guido van Rossum releases Python with built-in list sorting. Early versions use a comparison-based approach but lack the elegant key parameter.
2002
Timsort Created
Tim Peters designs Timsort for Python 2.3 — a hybrid of merge sort and insertion sort that excels on real-world data. It becomes Python's default sorting algorithm.
2004
sorted() with key Parameter
Python 2.4 introduces the built-in sorted() function with key and reverse parameters, replacing the older and less readable cmp approach.
2008
Python 3 Standardizes Key Functions
Python 3 removes the cmp parameter entirely, making key the standard way to customize sorting — a cleaner, more Pythonic design.

The central question this lesson addresses is: how do you sort data by something other than the default order? What if you want to sort words by their length, students by their grade, or products by price? The key parameter gives you that power in a single, clean line of Python.

Core Principles & Definitions

Before diving into examples, you need to understand a few foundational ideas about how sorted() works. Unlike the .sort() method which modifies a list in place, sorted() always returns a new list and leaves the original data unchanged. This makes it safe to use anywhere without worrying about side effects.

1

The sorted() Function

A built-in function that takes any iterable (list, tuple, string, etc.) and returns a new sorted list. Syntax: sorted(iterable, key=None, reverse=False)
2

The key Parameter

A function that is called on each element before comparison. It transforms elements for sorting purposes without changing the actual data in the output list.
3

The reverse Parameter

A boolean flag. When set to True, the sort order flips from ascending (smallest first) to descending (largest first).
4

Stability in Sorting

Python's sort is stable — when two elements have the same key value, they keep their original relative order. This matters when sorting by multiple criteria.
5

Lambda Functions

Small, anonymous functions written inline using lambda. They're commonly used as key functions because they're compact: lambda x: len(x)
✦ KEY TAKEAWAY
Think of the key function like a label maker. Imagine you have a pile of backpacks to arrange by weight. You don't rearrange the contents — you just stick a weight label on each one, sort by the labels, then line up the original backpacks in that order. The key function creates those temporary labels for sorting, but the items in your output list remain exactly as they were.

Visual Explanation

The diagram below shows how sorted() with a key function works step by step. The original list of words is transformed by the key function (len), sorted by those transformed values, and then the original elements are returned in the new order.

The key function (len) is applied to each element to produce a temporary sorting key. Elements are sorted by these keys, then the original elements (not the keys) are returned.

Notice something important in the diagram: the key function is applied to every element exactly once. Python does not call the key function repeatedly during comparisons. Instead, it creates a decorated version of the list, sorts that, then strips the decorations away. This is both efficient and elegant.

How It Works Under the Hood

Understanding the full signature of sorted() helps you use it with confidence. The function signature is straightforward, and each parameter has a clear role.

FUNCTION SIGNATURE
sorted(iterable, key=None, reverse=False)
iterable — any sequence (list, tuple, string, dict, set, generator). key — a function that takes one element and returns a comparison value. reverse — if True, the sort is in descending order.

The Decorate-Sort-Undecorate Pattern

Internally, Python uses a pattern called decorate-sort-undecorate (also known as the Schwartzian transform in other languages). Here is how it works in three phases:

  1. Decorate: For each element x in the iterable, compute key(x) and pair it with the original element to form (key(x), x).
  2. Sort: Sort the pairs by the first value (the key) using Timsort.
  3. Undecorate: Extract the original elements from the sorted pairs and return them as the final list.
TIME COMPLEXITY
O(n log n) comparisons + O(n) key evaluations
The key function is called exactly n times (once per element), not during every comparison. This is why key functions are efficient — even if sorting makes O(n log n) comparisons, the key is only computed O(n) times.

Common Key Functions

Commonly used key functions with sorted()
Key FunctionWhat It DoesExample
key=lenSorts by the length of each elementsorted(["hi", "hello", "hey"], key=len)
key=str.lowerCase-insensitive alphabetical sortsorted(["Banana", "apple"], key=str.lower)
key=absSorts by absolute value (distance from zero)sorted([-5, 3, -1, 4], key=abs)
key=lambda x: x[1]Sorts tuples/lists by their second elementsorted([("A", 3), ("B", 1)], key=lambda x: x[1])
key=lambda s: s.split()[-1]Sorts strings by their last wordsorted(["John Smith", "Ada Lovelace"], key=lambda s: s.split()[-1])

Sorting Complex Data Structures

The real power of key functions emerges when you work with complex data structures — lists of dictionaries, lists of tuples, or lists of custom objects. In real-world programs, you rarely sort simple lists of numbers. Instead, you sort records with multiple fields, and you need to choose which field to sort by.

Two ways to sort dictionaries: by a single key (name or grade), or by multiple keys using two stable sort passes. Python's stable sort guarantees that ties in the primary sort preserve the order from the secondary sort.
💡 Pro Tip: Tuple Keys for Multi-Level Sorting
Instead of using two sort passes, you can return a tuple from your key function. Python compares tuples element by element, so key=lambda s: (-s["grade"], s["name"]) sorts by grade descending (using negation) and then by name ascending, all in one call. The negative sign trick only works with numbers, though.

Worked Example

Let's walk through a complete, realistic example. Suppose you have a list of video games with their titles and ratings, and you want to display them sorted from highest to lowest rating.

Sorting Video Games by Rating (Descending)
1
Step 1 — Define the DataWe start with a list of tuples, where each tuple holds a game title and its rating out of 10: games = [("Zelda", 9.7), ("Minecraft", 9.2), ("Fortnite", 8.5), ("Elden Ring", 9.5), ("Among Us", 8.0)]
2
Step 2 — Identify the KeyEach element is a tuple like ("Zelda", 9.7). We want to sort by the rating, which is at index 1. Our key function will be lambda game: game[1]. This extracts the second element of each tuple.
3
Step 3 — Choose the Sort OrderWe want the highest rating first, so we set reverse=True. Without this, the default is ascending — lowest first.
4
Step 4 — Write the Coderanked = sorted(games, key=lambda game: game[1], reverse=True)
5
Step 5 — Trace the ExecutionPython calls the lambda on each tuple: 9.7, 9.2, 8.5, 9.5, 8.0. It sorts these values in descending order: 9.7, 9.5, 9.2, 8.5, 8.0. Then it returns the original tuples in this new order.
[("Zelda", 9.7), ("Elden Ring", 9.5), ("Minecraft", 9.2), ("Fortnite", 8.5), ("Among Us", 8.0)]
6
Step 6 — Verify the Original is UnchangedThe original games list is still in its original order. sorted() created a new list called ranked without modifying the input.
⚠️ Common Mistake
Don't write key=lambda game: game[1]() with parentheses after game[1]. The value 9.7 is a float, not a function — you can't call it. Also, don't write key=len() — pass the function itself (key=len), not the result of calling it.

sorted() vs .sort() and Other Approaches

Python offers several ways to sort data. Understanding when to use each approach is part of becoming a skilled programmer. The two main options are the built-in sorted() function and the list method .sort(). They share the same key and reverse parameters but behave differently in important ways.

Key differences between sorted() and .sort()
Featuresorted(iterable)list.sort()
ReturnsA new sorted listNone (modifies list in place)
Input typesAny iterable (list, tuple, string, dict, set, generator)Lists only
Original dataUnchanged (safe)Overwritten (destructive)
MemoryUses extra memory for the new listSorts in place — more memory efficient
ChainingCan be chained: sorted(data, key=len)[0]Cannot chain (returns None)
Best forWhen you need the original + sorted version, or sorting non-list iterablesWhen you only need the sorted version and want to save memory
✦ WHEN TO USE WHICH
Think of sorted() like making a photocopy of a document and then rearranging the copy — your original stays safe in the drawer. Think of .sort() like rearranging the pages of the original document itself. Use sorted() when in doubt — it's safer and more flexible.

Connection to Advanced Concepts

The key parameter in sorted() is your first encounter with a powerful programming concept: higher-order functions — functions that accept other functions as arguments. This idea appears throughout Python and computer science more broadly.

How sorted() concepts connect to advanced topics
This LessonAdvanced ConceptConnection
key=lambda x: x[1]Higher-order functionsPassing functions as arguments is foundational in functional programming
key=lenmap(), filter()These built-in functions also accept a function as their first argument
Sort stabilityMerge sort, Timsort internalsUnderstanding why stability matters leads to studying sorting algorithms
O(n log n) complexityBig-O analysisKnowing that sorting is O(n log n) is foundational to algorithm analysis
Lambda expressionsClosures, decoratorsLambdas are a stepping stone to more advanced function techniques in Python

As you advance in computer science, you'll encounter the operator module, which provides functions like operator.itemgetter() and operator.attrgetter() as faster, more readable alternatives to lambda functions for common key patterns. You'll also learn about custom comparison methods like __lt__ that let your own classes define how their instances should be sorted.

Practice Problems

PROBLEM 1 — CONCEPTUAL
What is the difference between sorted(words) and sorted(words, key=len)? Explain what each call sorts by and why the results would differ for the list ["banana", "fig", "cherry", "apple"].
PROBLEM 2 — BASIC CALCULATION
What does the following code output? Trace through it step by step. nums = [15, -3, 8, -12, 4] result = sorted(nums, key=abs) print(result)
PROBLEM 3 — INTERMEDIATE
You have a list of tuples representing students and their test scores: students = [("Emma", 91), ("Liam", 85), ("Sophia", 91), ("Noah", 78)] Write a single sorted() call that sorts students by score from highest to lowest. For students with the same score, sort alphabetically by name (ascending).
PROBLEM 4 — APPLIED
You're building a playlist app. Songs are stored as dictionaries: songs = [ {"title": "Blinding Lights", "artist": "The Weeknd", "plays": 3200}, {"title": "Levitating", "artist": "Dua Lipa", "plays": 2800}, {"title": "Stay", "artist": "The Kid LAROI", "plays": 3200}, {"title": "Peaches", "artist": "Justin Bieber", "plays": 1500} ] Write code to display the top songs sorted by play count (most played first). For songs with equal plays, sort alphabetically by title.
PROBLEM 5 — CRITICAL THINKING
A classmate writes this code to sort a list of strings case-insensitively in reverse order: words = ["Banana", "apple", "Cherry"] result = sorted(words, key=str.upper, reverse=True) Another classmate argues that key=str.lower should be used instead. Does it matter? Would the output differ? Also, explain why the original strings in the result are mixed-case even though the key converts them. What would happen if someone accidentally wrote key=str.upper() instead?

Summary

Python's sorted() function returns a new sorted list from any iterable without modifying the original data. The key parameter accepts a function that transforms each element into a comparison value — like key=len for sorting by length or key=lambda x: x[1] for sorting by the second element of a tuple. The reverse=True parameter flips the order from ascending to descending.

Key functions are called exactly once per element (not during every comparison), making them efficient at O(n) key evaluations plus O(n log n) comparisons. Python's stable sort guarantees that equal elements keep their original order, enabling multi-level sorting through either tuple keys or successive sort passes. Mastering sorted() with key functions is your gateway to higher-order functions and functional programming patterns throughout Python.

Varsity Tutors • Python • sorted() with Key Functions — Use sorted() with key and reverse parameters