Start learning free

LESSON 263 OF 673 · TUPLES, SORTING & BUILT-INS

Custom Sorting in Python: sorted with key

Lesson Read the full explanation

TL ; DR:

To sort by your own rule, give sorted a key. The key is a small function. It says what to sort each item by.


nums = [25, 13, 5, 41, 33]
print(sorted(nums, key=lambda n: (n % 10, n)))
# [41, 13, 33, 5, 25]

scores = [70, 95, 82]
print(sorted(scores, key=lambda s: -s))
# [95, 82, 70]


Full lesson:

You met sorted in the Shopping Cart project. It puts numbers from small to large and text from A to Z. Sometimes you need another order. The shortest word may have to come first, or the highest score.

For that, give sorted a key. The key is a small function. The sorted function calls it on every item. Then it sorts the items by what the key returned.

The function lambda w: len(w) is written in one line. It has no name. It gets one value, w, and returns len(w). It works like a def function with only a return line.

  • To sort by length, use key=lambda w: len(w).
  • For two rules, the key returns a tuple. With key=lambda n: (n % 10, n), each number gives its last digit, then itself. Tuples are compared item by item. So the numbers go by last digit first. Numbers with the same last digit then go from small to large.
  • To sort from high to low, use key=lambda s: -s. The biggest number has the smallest -s, so it comes first.
  • For plain numbers, sorted(scores, reverse=True) also sorts from high to low.

The sorted function makes a new list. The old list stays as it was.

The list method lst.sort(key=...) sorts the list itself instead. It returns None. So never write lst = lst.sort().


Your task

A pet shop sells toys. Their prices are in prices. Make a list named highFirst with the prices from high to low.

The shop's pets are in names. Make a list named byLastLetter with the names sorted by their last letter, in alphabetical order. Names with the same last letter go from A to Z.

The code already prints both, one item per line.

Expected output:

30
12
8
5
Bella
Luna
Bo
Coco
Max
Rex
STEP 1 OF 2
    Ctrl + Enter to check

    PYTHON · TUPLES, SORTING & BUILT-INS

    Custom Sorting in Python, explained

    What a key does

    By default, sorted puts numbers from small to large and text from A to Z. Often you need another order: the highest price first, the shortest word first, or names ordered by their last letter. For that, give sorted a key.

    The key is a small function. sorted calls it once on every item, then orders the items by what the key returned. The items themselves are not changed, and the list you get back still holds the original items.

    A lambda is a function written in one line, with no name. lambda w: len(w) takes one value, w, and returns len(w). It does the same as a def function that holds only a return line.

    words = ["pear", "fig", "banana", "kiwi"]
    print(sorted(words, key=lambda w: len(w)))
    print(sorted(words, key=len))
    
    ['fig', 'pear', 'kiwi', 'banana']
    ['fig', 'pear', 'kiwi', 'banana']
    

    Both lines give the same list. When an existing function such as len already does the job, you can pass it directly.

    High to low

    For numbers there are two ways. The first negates the key: the biggest number has the smallest -n, so it comes first. The second is the reverse=True option.

    scores = [70, 95, 82]
    print(sorted(scores, key=lambda s: -s))
    print(sorted(scores, reverse=True))
    
    [95, 82, 70]
    [95, 82, 70]
    

    Negating only works for numbers. You can't write -name for a string, so for text use reverse=True.

    Two rules at once

    When one rule isn't enough, let the key return a tuple. Python compares tuples item by item: it looks at the first items, and only when they are equal does it look at the second ones.

    nums = [25, 13, 5, 41, 33]
    print(sorted(nums, key=lambda n: (n % 10, n)))
    print(sorted(nums, key=lambda n: n % 10))
    
    [41, 13, 33, 5, 25]
    [41, 13, 33, 25, 5]
    

    The key (n % 10, n) gives each number its last digit first, then the number itself. So 41 comes first (last digit 1), then 13 and 33 (last digit 3, small to large), and 5 and 25 close the list (last digit 5, small to large).

    The second line uses only the last digit. Items with equal keys keep the order they had in the original list, because the sort is stable. That is why 25 stays before 5 there. If you want a particular order for ties, put it in the tuple as a second rule.

    sorted and sort

    sorted(items) makes a new list and leaves the old one as it was. The list method lst.sort(key=...) sorts the list itself and returns None.

    lst = [3, 1, 2]
    result = lst.sort(key=lambda n: -n)
    print(result)
    print(lst)
    
    None
    [3, 2, 1]
    

    That is why lst = lst.sort() is a bug: it replaces your list with None.

    The lesson's task

    A pet shop has prices and names. You need highFirst, the prices from high to low, and byLastLetter, the names ordered by their last letter, with names that share a last letter going from A to Z. The loops that print both are already in the starter code.

    The first list needs one rule: the key turns each price into -price. The second needs two rules, so the key returns a tuple. The last letter of a name is name[-1], because a negative index counts from the end. The second item of the tuple is the whole name.

    Here are the keys the second list uses:

    names = ["Rex", "Luna", "Bella", "Max", "Bo", "Coco"]
    print([(name[-1], name) for name in names])
    
    [('x', 'Rex'), ('a', 'Luna'), ('a', 'Bella'), ('x', 'Max'), ('o', 'Bo'), ('o', 'Coco')]
    

    Sorted by these tuples, the a names come first (Bella before Luna), then o (Bo before Coco), then x (Max before Rex). Here is the whole solution:

    prices = [12, 5, 30, 8]
    names = ["Rex", "Luna", "Bella", "Max", "Bo", "Coco"]
    
    highFirst = sorted(prices, key=lambda price: -price)
    for price in highFirst:
        print(price)
    
    byLastLetter = sorted(names, key=lambda name: (name[-1], name))
    for name in byLastLetter:
        print(name)
    

    It prints:

    30
    12
    8
    5
    Bella
    Luna
    Bo
    Coco
    Max
    Rex
    

    Common mistakes

    • Forgetting the second rule. With key=lambda name: name[-1] alone, ties keep their original order, and the result is ['Luna', 'Bella', 'Bo', 'Coco', 'Rex', 'Max']. Rex comes before Max only because it was first in the list.
    • Calling the key instead of passing it. Write key=len, not key=len().
    • Using reverse=True with the tuple key. It flips both rules, so the names come out as ['Rex', 'Max', 'Coco', 'Bo', 'Luna', 'Bella'], with Z to A inside each group.
    • Assigning the result of sort(). It returns None.

    Key takeaways

    • Give sorted a key function to choose what each item is sorted by.
    • Return a tuple from the key to apply several rules in order.
    • Use -n or reverse=True to sort numbers from high to low.
    • sorted returns a new list; sort changes the list and returns None.
    Keep going with Python500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free