{"id":"more-comprehensions-sets","slug":"sets","title":"Sets and set comprehensions","text":"Sometimes you only care which values there are, not how many times each one comes up. A **set** is a collection for that. Each value is in a set only once, and a set keeps no order. You write one in curly brackets, or make one out of a list with `set`, which drops the repeats:\n\n```pycon\n>>> colors = {\"red\", \"blue\", \"red\"}\n>>> len(colors)\n2\n>>> \"blue\" in colors\nTrue\n>>> colors.add(\"green\")\n>>> colors.add(\"red\")\n>>> len(colors)\n3\n>>> set([3, 1, 3, 2, 1])\n{1, 2, 3}\n```\n\nThe method `add` adds a value to a set, and adding a value that's already there changes nothing. An empty set is `set()`, because `{}` is an empty dictionary.\n\n### Sort a set before you print it\n\nA set has no order of its own. Small whole numbers usually come out in increasing order, but strings come out in a different order from one run of the program to the next. So whenever you print a set of strings, or go through one, sort it first. `sorted` gives a sorted list:\n\n```pycon\n>>> sorted({\"pear\", \"apple\", \"fig\"})\n['apple', 'fig', 'pear']\n```\n\n### Set comprehensions\n\nCurly brackets without a key and a colon make a **set comprehension**. The repeats disappear on their own:\n\n```python\nwords = [\"tree\", \"car\", \"house\", \"dog\", \"bike\", \"sun\"]\nlengths = {len(word) for word in words}\nprint(lengths)\nprint(len(lengths), \"different lengths\")\n```\n\n```output\n{3, 4, 5}\n3 different lengths\n```\n\nSix words, but only three different lengths. Here the set holds strings, so it's sorted before it's printed:\n\n```python\nwords = [\"tree\", \"car\", \"house\", \"dog\", \"bike\", \"cat\"]\nfirst_letters = sorted({word[0] for word in words})\nprint(first_letters)\n```\n\n```output\n['b', 'c', 'd', 'h', 't']\n```\n\nSo curly brackets make two kinds of comprehension: with `key: value` a dictionary, and with a single expression a set.\n\n### A set has no indexes\n\nSince a set keeps no order, there's no first or second item, and indexing stops the program:\n\n```python\nlengths = {3, 4, 5}\nprint(lengths[0])\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 2, in <module>\n    print(lengths[0])\n          ~~~~~~~^^^\nTypeError: 'set' object is not subscriptable\n```\n\n\"Subscriptable\" means that something can be indexed with square brackets. To get the values in order, make a sorted list first: `sorted(lengths)[0]` is the smallest.\n","task":"Fill in the blank so that `lengths` is the set of the different word lengths. The program should print:\n\n```\n{4, 5, 6}\n```\n","kind":"fill","seed":"words = [\"banana\", \"kiwi\", \"apple\", \"plum\", \"pear\"]\nlengths = {[[len(word)]] for word in words}\nprint(lengths)\n","solution":"words = [\"banana\", \"kiwi\", \"apple\", \"plum\", \"pear\"]\nlengths = {len(word) for word in words}\nprint(lengths)\n","hints":["The expression of a set comprehension is the value that goes into the set for each word.","The length of a word is `len(word)`."],"tests":[{"name":"Output","stdin":"","expect":"{4, 5, 6}","hidden":false}],"require":[],"forbid":[],"more":[{"task":"Write a function `used_letters(text)` that returns a sorted list of the different letters in `text`, all in lowercase, without spaces. Use a set comprehension, and sort the set into a list.\n\nFor example, this call:\n\n```python\nprint(used_letters(\"Hello World\"))\n```\n\nprints:\n\n```\n['d', 'e', 'h', 'l', 'o', 'r', 'w']\n```\n","kind":"code","seed":"def used_letters(text):\n    pass\n\n\nif __name__ == \"__main__\":\n    print(used_letters(\"Hello World\"))\n","solution":"def used_letters(text):\n    return sorted({c for c in text.lower() if c != \" \"})\n\n\nif __name__ == \"__main__\":\n    print(used_letters(\"Hello World\"))\n","hints":["Go through the characters of `text.lower()`, so the capitals become small letters, and filter out the spaces with `if c != \" \"`.","In curly brackets, the comprehension makes a set, so each letter is in it only once.","`sorted(...)` around the set gives a sorted list."],"tests":[{"name":"print(used_letters(\"Hello World\"))","stdin":"","call":"print(used_letters(\"Hello World\"))\n","expect":"['d', 'e', 'h', 'l', 'o', 'r', 'w']","hidden":false},{"name":"used_letters(\"banana bread\")","stdin":"","call":"used_letters(\"banana bread\")\n","expect":"['a', 'b', 'd', 'e', 'n', 'r']","hidden":true,"returns":true},{"name":"used_letters(\"A a A\")","stdin":"","call":"used_letters(\"A a A\")\n","expect":"['a']","hidden":true,"returns":true}],"require":[{"pattern":"\\{[^\\n]*\\bfor\\b","message":"Collect the letters with a set comprehension."},{"pattern":"\\bsorted\\s*\\(","message":"Sort the set into a list with `sorted`."}],"forbid":[]},{"task":"Write a function `common(first, second)` that returns a sorted list of the different values that are in both lists. Use a set comprehension.\n\nFor example, this call:\n\n```python\nprint(common([\"tea\", \"milk\", \"jam\", \"tea\"], [\"jam\", \"bread\", \"tea\"]))\n```\n\nprints:\n\n```\n['jam', 'tea']\n```\n","kind":"code","seed":"def common(first, second):\n    pass\n\n\nif __name__ == \"__main__\":\n    print(common([\"tea\", \"milk\", \"jam\", \"tea\"], [\"jam\", \"bread\", \"tea\"]))\n","solution":"def common(first, second):\n    return sorted({item for item in first if item in second})\n\n\nif __name__ == \"__main__\":\n    print(common([\"tea\", \"milk\", \"jam\", \"tea\"], [\"jam\", \"bread\", \"tea\"]))\n","hints":["Go through the first list and keep only the items that are also in the second: `if item in second`.","In curly brackets the comprehension makes a set, so `\"tea\"` is there only once even though the first list has it twice.","Return `sorted(...)` of the set, a sorted list."],"tests":[{"name":"print(common([\"tea\", \"milk\", \"jam\", \"tea\"], [\"jam\", \"bread\", \"tea\"]))","stdin":"","call":"print(common([\"tea\", \"milk\", \"jam\", \"tea\"], [\"jam\", \"bread\", \"tea\"]))\n","expect":"['jam', 'tea']","hidden":false},{"name":"common([5, 3, 9, 3, 1], [1, 3, 7, 3])","stdin":"","call":"common([5, 3, 9, 3, 1], [1, 3, 7, 3])\n","expect":"[1, 3]","hidden":true,"returns":true},{"name":"common([\"a\", \"b\"], [\"c\"])","stdin":"","call":"common([\"a\", \"b\"], [\"c\"])\n","expect":"[]","hidden":true,"returns":true}],"require":[{"pattern":"\\{[^\\n]*\\bfor\\b","message":"Collect the values with a set comprehension."}],"forbid":[]}]}