{"id":"functions-as-arguments-lambda","slug":"lambda","title":"Lambda expressions","text":"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:\n\n```python\ndef closest_first(guesses, secret):\n    def distance(guess):\n        return abs(guess - secret)\n\n    return sorted(guesses, key=distance)\n\n\nprint(closest_first([62, 41, 55, 30], 50))\nprint(closest_first([3, 9, 6], 7))\n```\n\n```output\n[55, 41, 62, 30]\n[6, 9, 3]\n```\n\n### A function without a name\n\nFor 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:\n\n```python\nlambda guess: abs(guess - secret)\n```\n\nAfter 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**.\n\nWith a lambda, `closest_first` is one line long, and a simple key needs no helper function at all:\n\n```python\ndef closest_first(guesses, secret):\n    return sorted(guesses, key=lambda guess: abs(guess - secret))\n\n\nprint(closest_first([62, 41, 55, 30], 50))\n\nnames = [\"bea\", \"Cal\", \"ann\", \"Dot\"]\nprint(sorted(names))\nprint(sorted(names, key=lambda name: name.lower()))\n```\n\n```output\n[55, 41, 62, 30]\n['Cal', 'Dot', 'ann', 'bea']\n['ann', 'bea', 'Cal', 'Dot']\n```\n\nThe 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.\n\nA lambda holds exactly one expression. Statements such as `return`, an `if` block or a loop don't fit in it:\n\n```python\nwords = [\"kiwi\", \"fig\"]\nprint(sorted(words, key=lambda word: return len(word)))\n```\n\n```crash\n  File \"main.py\", line 2\n    print(sorted(words, key=lambda word: return len(word)))\n                                         ^^^^^^\nSyntaxError: invalid syntax\n```\n\nLeave out the `return`. When the work needs more than one expression, write a function with `def` instead.\n\n### min and max with a key\n\n`min` and `max` take a `key` too. They compare the items by the values the key returns, but they return the item itself:\n\n```pycon\n>>> temperatures = [(\"Mon\", 14), (\"Tue\", 9), (\"Wed\", 17)]\n>>> max(temperatures, key=lambda day: day[1])\n('Wed', 17)\n>>> min(temperatures, key=lambda day: day[1])[0]\n'Tue'\n>>> max([\"sky\", \"ocean\", \"river\"], key=len)\n'ocean'\n```\n\nWhen several items share the best value, as `ocean` and `river` do, `min` and `max` return the first of them.\n","task":"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:\n\n```\n[30, 61, 42, 95, 17]\n```\n","kind":"fill","seed":"numbers = [42, 17, 30, 95, 61]\nprint(sorted(numbers, key=[[lambda]] n: [[n % 10]]))\n","solution":"numbers = [42, 17, 30, 95, 61]\nprint(sorted(numbers, key=lambda n: n % 10))\n","hints":["A function without a name starts with the word `lambda`.","After the colon comes the value to sort by. The last digit of `n` is the remainder of `n` divided by 10: `n % 10`."],"tests":[{"name":"Output","stdin":"","expect":"[30, 61, 42, 95, 17]","hidden":false}],"require":[],"forbid":[],"more":[{"task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"pets = [(\"Rex\", 7), (\"Mia\", 2), (\"Bo\", 11)]\nprint(min(pets, key=lambda pet: pet[1]))\nprint(max(pets, key=lambda pet: len(pet[0]))[0])\nprint(sorted(pets, key=lambda pet: pet[0][-1]))\n","solution":"pets = [(\"Rex\", 7), (\"Mia\", 2), (\"Bo\", 11)]\nprint(min(pets, key=lambda pet: pet[1]))\nprint(max(pets, key=lambda pet: len(pet[0]))[0])\nprint(sorted(pets, key=lambda pet: pet[0][-1]))\n","hints":["`min` compares the pets by their ages, `pet[1]`, but returns the whole tuple.","The second line compares the lengths of the names. Rex and Mia are both 3 letters long, and `max` returns the first of them; `[0]` then takes its name.","The last line sorts by the last letter of each name: x, a and o."],"tests":[{"name":"Output","stdin":"","expect":"('Mia', 2)\nRex\n[('Mia', 2), ('Bo', 11), ('Rex', 7)]","hidden":false}],"require":[],"forbid":[],"lines":["('Mia', 2)","Rex","[('Mia', 2), ('Bo', 11), ('Rex', 7)]"]},{"task":"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,\n\n```python\nprint(sort_by_last_name([\"Grace Murray Hopper\", \"Alan Turing\", \"Ada Lovelace\"]))\n```\n\nshould print:\n\n```\n['Grace Murray Hopper', 'Ada Lovelace', 'Alan Turing']\n```\n","kind":"code","seed":"def sort_by_last_name(names):\n    pass\n\n\nif __name__ == \"__main__\":\n    print(sort_by_last_name([\"Grace Murray Hopper\", \"Alan Turing\", \"Ada Lovelace\"]))\n","solution":"def sort_by_last_name(names):\n    return sorted(names, key=lambda name: name.split()[-1])\n\n\nif __name__ == \"__main__\":\n    print(sort_by_last_name([\"Grace Murray Hopper\", \"Alan Turing\", \"Ada Lovelace\"]))\n","hints":["The key gets one full name and must return its last word. `split()` cuts a name into a list of words.","Some names have three words, so the second word won't do. The last item of a list is at index `-1`, so the key is `lambda name: name.split()[-1]`.","Return what `sorted(names, key=...)` gives."],"tests":[{"name":"print(sort_by_last_name([\"Grace Murray Hopper\", \"Alan Turing\", \"Ada Lovelace\"]))","stdin":"","call":"print(sort_by_last_name([\"Grace Murray Hopper\", \"Alan Turing\", \"Ada Lovelace\"]))\n","expect":"['Grace Murray Hopper', 'Ada Lovelace', 'Alan Turing']","hidden":false},{"name":"sort_by_last_name([\"Linus Torvalds\", \"Guido van Rossum\", \"Margaret Hamilton\", \"Tim Berners-Lee\"])","stdin":"","call":"sort_by_last_name([\"Linus Torvalds\", \"Guido van Rossum\", \"Margaret Hamilton\", \"Tim Berners-Lee\"])\n","expect":"['Tim Berners-Lee', 'Margaret Hamilton', 'Guido van Rossum', 'Linus Torvalds']","hidden":true,"returns":true},{"name":"sort_by_last_name([\"Zoe Adams\", \"Al Zane\"])","stdin":"","call":"sort_by_last_name([\"Zoe Adams\", \"Al Zane\"])\n","expect":"['Zoe Adams', 'Al Zane']","hidden":true,"returns":true}],"require":[{"pattern":"\\blambda\\b","message":"Use a lambda expression as the key."}],"forbid":[]}]}