{"id":"comprehensions-filtering","slug":"filtering","title":"Picking items with if","text":"Sometimes the new list should have only some of the items. With a loop you'd put an `if` inside it:\n\n```python\nscores = [72, 45, 90, 38, 66]\npassed = []\nfor score in scores:\n    if score >= 50:\n        passed.append(score)\nprint(passed)\n```\n\n```output\n[72, 90, 66]\n```\n\nA list comprehension can do the same. The condition goes at the end:\n\n```python\nscores = [72, 45, 90, 38, 66]\npassed = [score for score in scores if score >= 50]\nprint(passed)\n```\n\n```output\n[72, 90, 66]\n```\n\nThe shape is now:\n\n```text\n[expression for item in series if condition]\n```\n\nOnly the items for which the condition is `True` make it into the new list. The others are skipped, so the new list can be shorter than the original, or even empty. This is called **filtering**. Here the expression is just `score`, so the items that pass go in as they are.\n\n### Filter and change at the same time\n\nThe expression can still change the items that pass the filter:\n\n```pycon\n>>> numbers = [3, 8, 5, 12, 7, 4]\n>>> [n for n in numbers if n % 2 == 0]\n[8, 12, 4]\n>>> [n * n for n in numbers if n % 2 == 0]\n[64, 144, 16]\n>>> [n for n in numbers if n > 100]\n[]\n```\n\nIn the second comprehension, 3, 5 and 7 are never squared at all. They're left out before the expression is worked out.\n\n### A filter as a guard\n\nThat order matters when the expression can fail. Here each team shares 40 pizza slices, and the comprehension works out how many slices each person gets. But two teams have 0 people, a mistake in the data, and dividing by 0 stops the program:\n\n```python\nteam_sizes = [4, 0, 5, 0, 10]\npizza_slices = [40 // size for size in team_sizes]\nprint(pizza_slices)\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 2, in <module>\n    pizza_slices = [40 // size for size in team_sizes]\n                    ~~~^^~~~~~\nZeroDivisionError: division by zero\n```\n\nA filter fixes it. For each size, Python checks the condition first, and only a size that passes gets as far as `40 // size`:\n\n```python\nteam_sizes = [4, 0, 5, 0, 10]\npizza_slices = [40 // size for size in team_sizes if size != 0]\nprint(pizza_slices)\n```\n\n```output\n[10, 8, 4]\n```\n\nThe condition can be anything that gives `True` or `False`, including conditions joined with `and` and `or`, and `in`:\n\n```pycon\n>>> words = [\"apple\", \"fig\", \"banana\", \"kiwi\", \"cherry\"]\n>>> [w for w in words if len(w) > 3 and \"a\" in w]\n['apple', 'banana']\n```\n","task":"Fill in the blank so that `freezing` holds only the temperatures below zero. The program should print:\n\n```\n[-2, -7, -1]\n```\n","kind":"fill","seed":"temperatures = [3, -2, 0, -7, 5, -1]\nfreezing = [t for t in temperatures [[if t < 0‖if 0 > t]]]\nprint(freezing)\n","solution":"temperatures = [3, -2, 0, -7, 5, -1]\nfreezing = [t for t in temperatures if t < 0]\nprint(freezing)\n","hints":["The condition comes at the end of the comprehension, after the word `if`.","A temperature below zero is one for which `t < 0` is true: the blank is `if t < 0`."],"tests":[{"name":"Output","stdin":"","expect":"[-2, -7, -1]","hidden":false}],"require":[],"forbid":[],"more":[{"task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"numbers = [5, 10, 15, 20]\nprint([n for n in numbers if n > 10])\nprint([n // 5 for n in numbers if n != 15])\nprint([n for n in numbers if n > 50])\n","solution":"numbers = [5, 10, 15, 20]\nprint([n for n in numbers if n > 10])\nprint([n // 5 for n in numbers if n != 15])\nprint([n for n in numbers if n > 50])\n","hints":["Start with the numbers that pass each condition. In the first line, which numbers are greater than 10?","In the second line, every number except 15 passes, and each one is divided by 5.","No number is greater than 50, so the last list has no items at all."],"tests":[{"name":"Output","stdin":"","expect":"[15, 20]\n[1, 2, 4]\n[]","hidden":false}],"require":[],"forbid":[],"lines":["[15, 20]","[1, 2, 4]","[]"]},{"task":"Write a function `words_with(words, letter)` that returns a new list of the words that contain the given letter, in their original order. Use a list comprehension.\n\nFor example, this call:\n\n```python\nprint(words_with([\"python\", \"java\", \"rust\", \"ruby\"], \"u\"))\n```\n\nprints:\n\n```\n['rust', 'ruby']\n```\n","kind":"code","seed":"def words_with(words, letter):\n    pass\n\n\nif __name__ == \"__main__\":\n    print(words_with([\"python\", \"java\", \"rust\", \"ruby\"], \"u\"))\n","solution":"def words_with(words, letter):\n    return [word for word in words if letter in word]\n\n\nif __name__ == \"__main__\":\n    print(words_with([\"python\", \"java\", \"rust\", \"ruby\"], \"u\"))\n","hints":["The words go into the new list as they are, so the expression is just `word`. The work is in the condition.","`letter in word` is `True` when the word contains the letter.","Put it together: `[word for word in words if ...]`."],"tests":[{"name":"print(words_with([\"python\", \"java\", \"rust\", \"ruby\"], \"u\"))","stdin":"","call":"print(words_with([\"python\", \"java\", \"rust\", \"ruby\"], \"u\"))\n","expect":"['rust', 'ruby']","hidden":false},{"name":"words_with([\"cat\", \"dog\", \"bird\", \"cow\"], \"o\")","stdin":"","call":"words_with([\"cat\", \"dog\", \"bird\", \"cow\"], \"o\")\n","expect":"['dog', 'cow']","hidden":true,"returns":true},{"name":"words_with([\"cat\", \"dog\"], \"z\")","stdin":"","call":"words_with([\"cat\", \"dog\"], \"z\")\n","expect":"[]","hidden":true,"returns":true}],"require":[{"pattern":"\\[[^\\n]*\\bfor\\b","message":"Build the new list with a list comprehension."}],"forbid":[{"pattern":"\\.append\\s*\\(","message":"Build the new list with a list comprehension instead of `append`."}]}]}