Python sorted(): Sorting Iterables with Custom Keys & Stability

The sorted(iterable, *, key=None, reverse=False) built-in function builds and returns a new sorted list from the elements of any iterable.

Non-Destructive Timsort: Unlike list.sort() which modifies the source list in place and returns None, sorted() leaves the original iterable untouched and operates on any collection (including tuples, strings, sets, and dictionary keys). It implements the adaptive, stable Timsort algorithm in O(N log N) worst-case time complexity. For reversing sequences without sorting, see reversed(), or filter items conditionally with filter().

1. Syntax & Formal Parameter Specifications 🔝

The sorted() function accepts one positional iterable and optional keyword arguments:

# Formal syntax of built-in sorted()
sorted_list = sorted(iterable, /, *, key=None, reverse=False)
Parameter Type Accepted Behavioral Details
iterable Iterable[T] Any iterable sequence or collection (such as list, tuple, string, set, dict keys, or generator).
key Callable or None Optional single-argument function (e.g. len, str.lower) extracting a comparison key from each element. Defaults to None.
reverse bool Optional boolean flag. If set to True, items are sorted in descending order. Defaults to False.
Return Value list Always returns a newly allocated list containing all elements in sorted order.

2. Basic Usage: Numbers, Strings & Iterables 🔝

Pass any iterable collection to sorted() to generate a new ordered list without modifying the input:

# 1. Sorting a numeric list
numbers = [12, 3, 8, 7, 14]
sorted_nums = sorted(numbers)

print("Sorted copy:  ", sorted_nums)
print("Original list:", numbers)

# 2. Sorting strings and characters
fruits = ["Orange", "Banana", "Apple", "Mango"]
print("Sorted fruits: ", sorted(fruits))

text = "plus2net"
print("Sorted letters:", sorted(text))

Output:

Sorted copy:   [3, 7, 8, 12, 14]
Original list: [12, 3, 8, 7, 14]
Sorted fruits:  ['Apple', 'Banana', 'Mango', 'Orange']
Sorted letters: ['2', 'e', 'l', 'n', 'p', 's', 't', 'u']

3. Descending Sort with reverse=True 🔝

Pass reverse=True to arrange items in descending order directly:

# Descending sort using reverse=True
numbers = [12, 3, 8, 7, 14]
descending_nums = sorted(numbers, reverse=True)
print("Descending numbers:", descending_nums)

fruits = ["Orange", "Banana", "Apple", "Mango"]
print("Descending fruits: ", sorted(fruits, reverse=True))

Output:

Descending numbers: [14, 12, 8, 7, 3]
Descending fruits:  ['Orange', 'Mango', 'Banana', 'Apple']

4. Custom Sorting with key Functions 🔝

The key parameter accepts a callable function computing comparison proxy values:

# 1. Sorting by length using built-in len as key
words = ["Three", "One", "Seven", "thirtyfive", "Two"]
by_length = sorted(words, key=len)
print("Sorted by length:", by_length)

# 2. Case-insensitive sorting with str.lower
mixed_cases = ["banana", "Apple", "orange", "Cherry"]
case_insensitive = sorted(mixed_cases, key=str.lower)
print("Case-insensitive:", case_insensitive)

# 3. Custom key function for tuples
records = [(3, 5), (2, 1), (8, 4), (3, 7)]
def get_second(item):
    return item[1]

by_second = sorted(records, key=get_second)
print("Sorted by 2nd item:", by_second)

Output:

Sorted by length: ['One', 'Two', 'Three', 'Seven', 'thirtyfive']
Case-insensitive: ['Apple', 'banana', 'Cherry', 'orange']
Sorted by 2nd item: [(2, 1), (8, 4), (3, 5), (3, 7)]
Pro-Tip (Key Call Efficiency): Python guarantees that the key function is called exactly once for each input element. This Schwartzian Transform optimization prevents repeated key computations during element comparisons.

5. sorted() vs. list.sort() Comparison 🔝

Compare non-destructive copying with in-place list mutation:

Feature sorted(iterable) list.sort()
Input Scope Any iterable (tuple, set, dict, string, generator) Exclusively list instances
Modification Non-destructive (leaves source intact) In-place mutation (modifies list directly)
Return Value New list instance None
Memory Overhead O(N) memory to allocate new list copy O(1) auxiliary memory (sorts in-place)
# sorted() creates a new list; list.sort() mutates in-place
original_data = [5, 2, 9, 1]

# sorted() leaves original untouched and returns a new list
result_copy = sorted(original_data)
print("result_copy:", result_copy)
print("original_data:", original_data)

# list.sort() modifies original and returns None
ret_val = original_data.sort()
print("original_data after sort():", original_data)
print("return value of sort():    ", ret_val)

Output:

result_copy: [1, 2, 5, 9]
original_data: [5, 2, 9, 1]
original_data after sort(): [1, 2, 5, 9]
return value of sort():     None

6. Production Recipes: Multi-Criteria & Object Sorting 🔝

Multi-level comparisons across dictionary fields or custom objects:

# Recipe A: Multi-attribute sorting using operator.itemgetter
from operator import itemgetter

employees = [
    {"name": "Alice", "dept": "HR", "salary": 75000},
    {"name": "Bob", "dept": "IT", "salary": 92000},
    {"name": "Charlie", "dept": "IT", "salary": 85000},
    {"name": "Diana", "dept": "HR", "salary": 80000},
]

# Sort by department ascending, then by salary descending
by_dept_salary = sorted(employees, key=lambda e: (e["dept"], -e["salary"]))
for emp in by_dept_salary:
    print(f"{emp['dept']} | {emp['salary']} | {emp['name']}")

# Recipe B: Stable sorting with custom object keys
class Student:
    def __init__(self, name: str, grade: int, gpa: float):
        self.name = name
        self.grade = grade
        self.gpa = gpa

students = [Student("Amy", 10, 3.8), Student("Ben", 11, 3.9), Student("Cara", 10, 3.95)]
top_students = sorted(students, key=lambda s: s.gpa, reverse=True)
print("Top student:", top_students[0].name, top_students[0].gpa)

Output:

HR | 80000 | Diana
HR | 75000 | Alice
IT | 92000 | Bob
IT | 85000 | Charlie
Top student: Cara 3.95

7. Common Pitfalls & Developer Traps 🔝

Frequent Traps with sorted()
  • Unorderable Mixed Types: In Python 3, sorting collections with uncomparable types (like integers and strings) raises TypeError: '<' not supported between instances. Provide a custom key=str function if needed.
  • Assuming Return Type Matches Input: Passing a set, tuple, or string to sorted() always yields a list, never a set or string. Use "".join(sorted(text)) or tuple(sorted(t)) when you need the original container type.
  • Modifying Iterable During Sorting: While sorted() copies items quickly into an internal array, modifying the underlying data structure in a concurrent thread can lead to inconsistent state.
# Pitfall 1: Sorting unorderable mixed types in Python 3
try:
    sorted([10, "apple", 5])
except TypeError as err:
    print("Mixed types error:", err)

# Pitfall 2: Sorting sets returns a list, not a set
unique_numbers = {9, 1, 4, 3}
sorted_result = sorted(unique_numbers)
print("Type of sorted result:", type(sorted_result), sorted_result)

Output:

Mixed types error: '<' not supported between instances of 'str' and 'int'
Type of sorted result:  [1, 3, 4, 9]

8. Interactive Notebook & Practice Exercises 🔝

Practice stable sorting, multi-criteria lambdas, and benchmark sorting performance in our companion Jupyter Notebook:

Interactive Companion Jupyter Notebook

Explore interactive code cells, benchmark sorted() vs list.sort(), implement multi-field dictionary sorting, and run self-validating assertions.

View on GitHub Run in Google Colab

Self-Verifying Assertion Suite

Run these unit checks directly in Python or your local environment to verify sorted() mechanics:

def test_sorted_mechanics():
    # 1. Basic sorting
    assert sorted([5, 1, 3]) == [1, 3, 5]
    assert sorted([5, 1, 3], reverse=True) == [5, 3, 1]
    
    # 2. Key function with length
    words = ["bb", "a", "ccc"]
    assert sorted(words, key=len) == ["a", "bb", "ccc"]
    
    # 3. Tuple key multi-criteria
    data = [(1, "b"), (2, "a"), (1, "a")]
    assert sorted(data) == [(1, "a"), (1, "b"), (2, "a")]
    
    # 4. Guaranteeing original iterable immutability
    original = [4, 2, 8]
    res = sorted(original)
    assert original == [4, 2, 8]
    assert res == [2, 4, 8]
    
    print("All sorted() unit assertions passed! 100% verified.")

test_sorted_mechanics()

Output:

All sorted() unit assertions passed! 100% verified.
reversed()

Returns a reverse iterator over sequence elements without creating a reversed copy.

filter()

Extracts elements from an iterable matching a boolean predicate condition.

map()

Applies a function to all elements in an iterable, returning a lazy transformation iterator.

len()

Calculates the total number of items in a sequence or collection.




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer