<jupyter_start><jupyter_text>SetsThe **set** is a data type in Python which stores only unique elements in no particular order. In this way, the set works much like a *mathematical set*, and even has methods that perform set operations.  Defining a setSets in Python are defined with curly braces `{}`, and each element is separated by a comma, like with lists and tuples.<jupyter_code>pets = {'dog', 'cat', 'hamster', 'fish', 'snake'}
mammals = {'human', 'dog', 'cat', 'hamster', 'whale'}
scales = {'snake', 'alligator', 'pangolin', 'snake', 'fish'}
non_animals = {42, 'galaxy', None, False, ('Microsoft', 'Apple', 'Google')}<jupyter_output><empty_output><jupyter_text>In the above example, we can see that the `set` doesn't care what type our elements are, we can even mix types in a single set (like with the tuple and list). You may have notices that we specified `'snake'` twice in the `scales` set. Let's print that set:<jupyter_code>print(scales)<jupyter_output>{'pangolin', 'alligator', 'snake', 'fish'}<jupyter_text>You may also notice that the `scales` set is now in a different order (or it may be in the same order by coincidence). This is because sets are *unordered*, meaning they cannot be indexed like the `string`, `tuple` and `list`.<jupyter_code>scales[2]<jupyter_output><empty_output><jupyter_text>Since sets only hold unique objects, it doesn't matter how many times we specify an element, it will only be recorded once! This makes sets a bad way to keep track of a coin-flip contest.<jupyter_code>results = {'heads', 'tails', 'tails', 'tails', 'heads', 'tails', 'heads', 
           'tails','heads', 'tails', 'heads', 'tails'}
print(results)<jupyter_output>{'tails', 'heads'}<jupyter_text>But it does make sets a great way to quickly see how many different items are in our poorly organized shopping cart.<jupyter_code>cart = {'apple', 'pear', 'tofu', 'milk', 'apple', 'apple', 'orange', 'rice', 
        'pasta', 'pear', 'milk', 'pear', 'grapes', 'orange', 'apple'}
print(cart)
print("We bought {} different items".format(len(cart)))<jupyter_output>{'pasta', 'grapes', 'pear', 'apple', 'milk', 'orange', 'rice', 'tofu'}
We bought 8 different items<jupyter_text>Hashable typesThe exception to our brash statement that the "set doesn't care what type our elements are" is for types that Python claims are *unhashable*.<jupyter_code>broken_set = {[1, 2, 3]}<jupyter_output><empty_output><jupyter_text>Here, the error tells us that the `list` type is *unhashable*. This is because lists are *mutable*, meaning that can be changed later. Make sure when you're using sets that you use immutable types like `int`, `float`, `string` and `tuple`.   Converting to setTo quickly see the unique elements of a list or tuple, we can convert it to a set with the built-in `set()` function. The following example will show how useful this can be.Say a shoe store sells the many different sizes of shoes on a given day and their bookkeeping is simply a list of the sizes sold. We want to see which sizes aren't selling, so we use the `count()` method to find which shoe sizes are missing.<jupyter_code># A shoe stores sells shoes of the following sizes on a certain day
shoe_sizes = [7, 8, 9, 6, 7, 7, 9, 7, 8, 10, 13, 7, 6, 7, 8, 9, 6, 7, 
              7, 9, 7, 8, 10, 13, 7, 6, 7, 8, 9, 6, 7, 7, 9, 7, 14, 5,
              8, 10, 13, 7, 6, 7, 8, 9, 6, 7, 7, 9, 7, 8, 10, 13, 7, 6,
              7, 8, 9, 6, 7, 7, 9, 7, 8, 10, 13, 7, 6, 7, 8, 9, 6, 7, 7, 
              9, 7, 8, 10, 13, 7, 6]

# We can print how many of each shoe was sold with count
print(shoe_sizes.count(6),
      shoe_sizes.count(7),
      shoe_sizes.count(8),
      shoe_sizes.count(9),
      shoe_sizes.count(10),
      shoe_sizes.count(11),
      shoe_sizes.count(12),
      shoe_sizes.count(13))<jupyter_output>12 30 12 12 6 0 0 6<jupyter_text>Since we only care about the shoes that are not selling for this example, we can simply use a set!<jupyter_code>sold_sizes = set(shoe_sizes)
print(sold_sizes)<jupyter_output>{5, 6, 7, 8, 9, 10, 13, 14}<jupyter_text>This `shoe_set` shows the 8 sizes that were sold that day. Now we want to see which of our sizes were *not* sold. There's a set method for that!Remember, you can always use the `help()` function to see methods of an object in Python<jupyter_code>help(set)<jupyter_output><empty_output><jupyter_text>Set methods In the help info, we might notice that we can use set operations like `union()` and `difference()` on our set. Let's use the set difference to see which shoes were not sold on a give day.<jupyter_code>all_sizes = {6, 7, 8, 9, 10, 11, 12, 13}
not_sold = all_sizes.difference(sold_sizes)
print(not_sold)<jupyter_output>{11, 12}<jupyter_text>Sets also allow us to use math operators to compare sets, so the following is the exact same as above<jupyter_code>print(all_sizes - sold_sizes)<jupyter_output>{11, 12}<jupyter_text>Now we know that size 11 and size 12 were the only shoe sizes not sold.Let's return to our animal sets from the start of this chapter. Say we want to add to a set. We can do this with the `add()` method.<jupyter_code>pets = {'dog', 'cat', 'hamster', 'fish', 'snake'}
mammals = {'human', 'dog', 'cat', 'hamster', 'whale'}
scales = {'snake', 'alligator', 'pangolin', 'snake', 'fish'}

mammals.add('koala')
print(mammals)<jupyter_output>{'hamster', 'cat', 'whale', 'dog', 'human', 'koala'}<jupyter_text>If we want to take the unions of two sets, we can use `union()` or `|`.<jupyter_code>all_animals = pets | mammals | scales
print(all_animals)<jupyter_output>{'fish', 'alligator', 'snake', 'hamster', 'pangolin', 'cat', 'whale', 'dog', 'human', 'koala'}<jupyter_text>We can also take the set intersection (`.intersection()` or `&`), to see the overlap between sets.<jupyter_code>mammalian_pets = pets & mammals
print(mammalian_pets)

scaly_pets = pets & scales
print(scaly_pets)<jupyter_output>{'cat', 'hamster', 'dog'}
{'fish', 'snake'}
{'fraction_non_alphanumeric': 0.13115586393636824, 'fraction_numerical': 0.02707733965137925, 'mean_word_length': 4.921843687374749, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '227862', 'license': 'MIT', 'n_tokens_mistral': 2169, 'n_tokens_neox': 1961, 'n_words': 804, 'path': 'content/03_python/07/01_set.ipynb', 'repo_name': 'Bellatrix12/spirl', 'size': '5909'}