Python Arena
Step 2 of 4

Lambda expressions

The guessing game's secret number won't always be 50. A function closest_first(guesses, secret) can take it as a parameter, but then its key function needs the secret number too. The answer is to define the key function inside closest_first. A function defined inside another one can use that function's variables and parameters, such as secret, and it exists only there, so it doesn't clutter the rest of the program:

def closest_first(guesses, secret):
    def distance(guess):
        return abs(guess - secret)

    return sorted(guesses, key=distance)


print(closest_first([62, 41, 55, 30], 50))
print(closest_first([3, 9, 6], 7))
Output
[55, 41, 62, 30]
[6, 9, 3]

A function without a name

For a function this small, Python has a shorter way to write it: a lambda expression. It makes a function right where you need it, without def and without a name:

lambda guess: abs(guess - secret)

After the word lambda come the parameters, then a colon, then one expression. Calling the function gives the value of that expression. There's no return: the value is returned automatically. Because a function made this way has no name of its own, it's also called an anonymous function.

With a lambda, closest_first is one line long, and a simple key needs no helper function at all:

def closest_first(guesses, secret):
    return sorted(guesses, key=lambda guess: abs(guess - secret))


print(closest_first([62, 41, 55, 30], 50))

names = ["bea", "Cal", "ann", "Dot"]
print(sorted(names))
print(sorted(names, key=lambda name: name.lower()))
Output
[55, 41, 62, 30]
['Cal', 'Dot', 'ann', 'bea']
['ann', 'bea', 'Cal', 'Dot']

The names show why a key is handy for words too. In Python's natural order every capital letter comes before every small letter, so Cal lands before ann. Sorting by the lowercase form of each name gives the order a person expects, and the names keep their capitals.

A lambda holds exactly one expression. Statements such as return, an if block or a loop don't fit in it:

words = ["kiwi", "fig"]
print(sorted(words, key=lambda word: return len(word)))
Python stops with
  File "main.py", line 2
    print(sorted(words, key=lambda word: return len(word)))
                                         ^^^^^^
SyntaxError: invalid syntax

Leave out the return. When the work needs more than one expression, write a function with def instead.

min and max with a key

min and max take a key too. They compare the items by the values the key returns, but they return the item itself:

In the Python interpreter
>>> temperatures = [("Mon", 14), ("Tue", 9), ("Wed", 17)]
>>> max(temperatures, key=lambda day: day[1])
('Wed', 17)
>>> min(temperatures, key=lambda day: day[1])[0]
'Tue'
>>> max(["sky", "ocean", "river"], key=len)
'ocean'

When several items share the best value, as ocean and river do, min and max return the first of them.

Your task

Challenge 1 of 3

Fill in the two blanks so that the numbers are sorted by their last digit (the remainder when you divide by 10). Use a lambda expression whose parameter is n. The program should print:

[30, 61, 42, 95, 17]

Challenge 2

What does this program print? Type each line it prints.

Challenge 3

Write a function sort_by_last_name(names) that gets a list of full names, such as "Ada Lovelace" or "Grace Murray Hopper", and returns a new list sorted by the last names. The last name is the last word of a full name, however many words it has: "Grace Murray Hopper" goes under Hopper. Use a lambda expression as the key. For example,

print(sort_by_last_name(["Grace Murray Hopper", "Alan Turing", "Ada Lovelace"]))

should print:

['Grace Murray Hopper', 'Ada Lovelace', 'Alan Turing']