Higher-order functions and lambdas

INPUT · Slides

Find the best in one line

01 / 07

The shape you wrote by hand in chapter 2

"Find whoever scored highest." You may remember doing it in the chapter 2 review.

Make the first one the winner for now, and swap whenever something beats it. That was the shape.

Being able to write it matters, but writing it out every time is a chore.

register = [    {"name": "Yui", "score": 90},    {"name": "Haruto", "score": 60},    {"name": "Minato", "score": 75},]best = register[0]for person in register:    if person["score"] > best["score"]:        best = personprint(best["name"])

Result

Yui

02 / 07

max and min

Python comes with max and min already. Hand either one a list and you get back the biggest or the smallest.

For a list of numbers, that is the end of it.

scores = [80, 45, 95]print(max(scores))print(min(scores))

Result

95
45

03 / 07

A list of dictionaries is a problem

So what happens if you hand that register straight to max? You get an error.

There is no deciding which of two dictionaries is the bigger. Python does not guess for you — when it does not know how to compare, it says so honestly.

register = [    {"name": "Yui", "score": 90},    {"name": "Haruto", "score": 60},]print(max(register))

Result

TypeError: '>' not supported between instances of 'dict' and 'dict'

04 / 07

Use key to say what to compare

The very same key you gave sorted can be given to max and min.

Write key=lambda p: p["score"] and it means "take p["score"] out of each person p and compare by that number".

The five lines from the previous slide come to this one.

register = [    {"name": "Yui", "score": 90},    {"name": "Haruto", "score": 60},    {"name": "Minato", "score": 75},]best = max(register, key=lambda p: p["score"])print(best["name"])

Result

Yui

05 / 07

What comes back is the item itself

This one is easy to get the wrong way round, so let us be plain about it.

What max(register, key=...) gives back is not the highest score. It is the item that had that score — the whole dictionary.

So the name and the score are both there to take out. Given that the question was "who scored highest", that is a very welcome way for it to behave.

register = [    {"name": "Yui", "score": 90},    {"name": "Haruto", "score": 60},]best = max(register, key=lambda p: p["score"])print(best)print(best["score"])

Result

{'name': 'Yui', 'score': 90}
90

06 / 07

min and len work the same

min is used exactly as max is. Reach for it when you want the cheapest thing.

And as with sorted, what you hand to key need not be a lambda. For the longest name, key=len is enough.

items = [    {"name": "apple", "price": 300},    {"name": "orange", "price": 100},]cheapest = min(items, key=lambda i: i["price"])print(cheapest["name"])names = ["Haruto", "Yui", "Minato"]print(max(names, key=len))

Result

orange
Haruto

07 / 07

The counting-up tools are all here

sum belongs with max and min. Hand it a list of numbers and the total comes back. What you were adding up into total in chapter 2 becomes one line.

Mind that sum has no key. Build the thing you want totalled yourself and hand that over — a job for a comprehension.

By now you should see that handing a function to key is the same shape across all three tools. In the next group come map and filter, and then handing a function to one of your own.

register = [    {"name": "Yui", "score": 90},    {"name": "Haruto", "score": 60},    {"name": "Minato", "score": 75},]scores = [p["score"] for p in register]print(sum(scores))print(sum(scores) // len(scores))print(max(scores) - min(scores))

Result

225
75
30