{"id":"for-loops-best-item","slug":"best-item","title":"The best item so far","text":"`max` and `min` know only one kind of best: the greatest or the smallest value. Often you want another kind: the longest word, the day with the most rain, the number closest to a target. Then you write the search yourself. The trick is one variable, set before the loop, that holds **the best item so far**. Every item is compared with it, and the winner of each comparison stays:\n\n```python\ndef longest(words: list) -> str:\n    best = words[0]\n    for word in words:\n        if len(word) > len(best):\n            best = word\n    return best\n\n\nprint(longest([\"fig\", \"banana\", \"kiwi\", \"cherry\"]))\n```\n\n```output\nbanana\n```\n\n`best` starts as the first word, so there's always a real word to compare with. In each round, a word that is longer than `best` takes its place. When the loop ends, every word has had its turn, so `best` is the longest of all. `cherry` is as long as `banana`, but not longer, so the first of the two stays.\n\n### Where to start\n\nStart the helper variable from an item of the list, not from a number you made up. A start of 0 looks harmless, but it breaks whenever no item can beat it: for the warmest, a list where every item is below 0; for the coldest, a list where every item is above 0:\n\n```python\ndef coldest(temperatures: list) -> int:\n    best = 0\n    for t in temperatures:\n        if t < best:\n            best = t\n    return best\n\n\ndef warmest(temperatures: list) -> int:\n    best = 0\n    for t in temperatures:\n        if t > best:\n            best = t\n    return best\n\n\nwinter = [-8, -3, -12, -5]\nsummer = [21, 18, 25]\nprint(coldest(winter))\nprint(warmest(winter))\nprint(coldest(summer))\n```\n\n```output\n-12\n0\n0\n```\n\nThe warmest winter temperature isn't 0: it's -3. The coldest summer temperature isn't 0 either: it's 18. In both wrong answers no temperature beat the start value 0, so 0 was returned, though it isn't even in the list. With `best = temperatures[0]`, both functions are right for any list.\n\n### Remembering where the best item is\n\nTo know where the best item is, and not only what it is, remember its index. Go through the indexes, and keep the index of the best item so far:\n\n```python\ndef rainiest_day(rain: list) -> int:\n    best = 0\n    for i in range(len(rain)):\n        if rain[i] > rain[best]:\n            best = i\n    return best + 1\n\n\nweek = [2, 0, 14, 5, 14, 1, 0]\nprint(\"Most rain on day\", rainiest_day(week))\n```\n\n```output\nMost rain on day 3\n```\n\nHere `best` is an index, so starting it from 0 is right: it means the first day. The function returns `best + 1` because people count days from 1.\n","task":"Fill in the blanks so that `first_in_dictionary(words)` returns the word that comes first in alphabetical order when capital letters don't matter, as in a dictionary. (`min` won't do here: it puts every word that starts with a capital letter before the words in small letters.) For example, `first_in_dictionary([\"melon\", \"Cherry\", \"apple\"])` returns `'apple'`.\n","kind":"fill","seed":"def first_in_dictionary(words: list) -> str:\n    best = words[0]\n    for word in words:\n        if word.lower() < [[best.lower()]]:\n            best = [[word]]\n    return best\n\n\nif __name__ == \"__main__\":\n    print(first_in_dictionary([\"melon\", \"Cherry\", \"apple\"]))\n","solution":"def first_in_dictionary(words: list) -> str:\n    best = words[0]\n    for word in words:\n        if word.lower() < best.lower():\n            best = word\n    return best\n\n\nif __name__ == \"__main__\":\n    print(first_in_dictionary([\"melon\", \"Cherry\", \"apple\"]))\n","hints":["Compare both words in small letters, so that capital letters don't change the order: the word in the loop is already written as `word.lower()`.","The other side of `<` is the best word so far, in small letters too. When the word comes earlier, it becomes the new `best` (the word itself, as it was written)."],"tests":[{"name":"first_in_dictionary([\"melon\", \"Cherry\", \"apple\"])","stdin":"","call":"first_in_dictionary([\"melon\", \"Cherry\", \"apple\"])\n","expect":"'apple'","hidden":false,"returns":true},{"name":"first_in_dictionary([\"one\"])","stdin":"","call":"first_in_dictionary([\"one\"])\n","expect":"'one'","hidden":true,"returns":true},{"name":"first_in_dictionary([\"kiwi\", \"Banana\", \"berry\", \"Apricot\"])","stdin":"","call":"first_in_dictionary([\"kiwi\", \"Banana\", \"berry\", \"Apricot\"])\n","expect":"'Apricot'","hidden":true,"returns":true},{"name":"first_in_dictionary([\"Zebra\", \"yak\", \"Walrus\"])","stdin":"","call":"first_in_dictionary([\"Zebra\", \"yak\", \"Walrus\"])\n","expect":"'Walrus'","hidden":true,"returns":true}],"require":[],"forbid":[],"more":[{"task":"Write the function `coldest_day(temperatures: list) -> int`, which returns the number of the day with the lowest temperature. Days are numbered from 1. If several days are equally cold, return the first of them. For example, `coldest_day([5, -2, 3, -2])` returns `2`.\n","kind":"code","seed":"def coldest_day(temperatures: list) -> int:\n    pass\n\n\nif __name__ == \"__main__\":\n    print(coldest_day([5, -2, 3, -2]))\n","solution":"def coldest_day(temperatures: list) -> int:\n    best = 0\n    for i in range(len(temperatures)):\n        if temperatures[i] < temperatures[best]:\n            best = i\n    return best + 1\n\n\nif __name__ == \"__main__\":\n    print(coldest_day([5, -2, 3, -2]))\n","hints":["Remember the index of the coldest day so far, starting from 0, and go through the indexes with `range(len(temperatures))`.","When `temperatures[i] < temperatures[best]`, set `best = i`. Using `<` and not `<=` keeps the first of equally cold days.","Days are counted from 1, so return `best + 1`."],"tests":[{"name":"coldest_day([5, -2, 3, -2])","stdin":"","call":"coldest_day([5, -2, 3, -2])\n","expect":"2","hidden":false,"returns":true},{"name":"coldest_day([10])","stdin":"","call":"coldest_day([10])\n","expect":"1","hidden":true,"returns":true},{"name":"coldest_day([3, 8, 1, 4, 0, 9])","stdin":"","call":"coldest_day([3, 8, 1, 4, 0, 9])\n","expect":"5","hidden":true,"returns":true},{"name":"coldest_day([-1, -4, -7])","stdin":"","call":"coldest_day([-1, -4, -7])\n","expect":"3","hidden":true,"returns":true}],"require":[],"forbid":[]},{"task":"Write the function `closest_to(numbers: list, target: int) -> int`, which returns the number in the list that is closest to `target`. If two numbers are equally close, return the one that comes first. For example, `closest_to([10, 25, 18, 40], 20)` returns `18`.\n\nPython's function `abs` helps here: it returns a number without its minus sign, so `abs(18 - 20)` and `abs(22 - 20)` are both `2`, the distance from 20.\n","kind":"code","seed":"def closest_to(numbers: list, target: int) -> int:\n    pass\n\n\nif __name__ == \"__main__\":\n    print(closest_to([10, 25, 18, 40], 20))\n","solution":"def closest_to(numbers: list, target: int) -> int:\n    best = numbers[0]\n    for number in numbers:\n        if abs(number - target) < abs(best - target):\n            best = number\n    return best\n\n\nif __name__ == \"__main__\":\n    print(closest_to([10, 25, 18, 40], 20))\n","hints":["Start with `best = numbers[0]`, the best number so far.","A number is closer than `best` when `abs(number - target) < abs(best - target)`.","Use `<`, not `<=`, so that the first of two equally close numbers stays the best."],"tests":[{"name":"closest_to([10, 25, 18, 40], 20)","stdin":"","call":"closest_to([10, 25, 18, 40], 20)\n","expect":"18","hidden":false,"returns":true},{"name":"closest_to([7], 100)","stdin":"","call":"closest_to([7], 100)\n","expect":"7","hidden":true,"returns":true},{"name":"closest_to([1, 9, 11, 3], 10)","stdin":"","call":"closest_to([1, 9, 11, 3], 10)\n","expect":"9","hidden":true,"returns":true},{"name":"closest_to([-5, -1, 4], 0)","stdin":"","call":"closest_to([-5, -1, 4], 0)\n","expect":"-1","hidden":true,"returns":true}],"require":[],"forbid":[]}]}