From 67f1d41cd220b219bbeb17ea24a28b30ac6a0a0b Mon Sep 17 00:00:00 2001 From: Matt Graham Date: Thu, 27 Oct 2022 15:11:10 +0100 Subject: [PATCH] Updating material in dictionaries notebook --- 01-beginner/028dictionaries.ipynb | 183 +++++++++++++----------------- 1 file changed, 80 insertions(+), 103 deletions(-) diff --git a/01-beginner/028dictionaries.ipynb b/01-beginner/028dictionaries.ipynb index 3896abd..96e74c2 100644 --- a/01-beginner/028dictionaries.ipynb +++ b/01-beginner/028dictionaries.ipynb @@ -4,35 +4,25 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Dictionaries" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The Python Dictionary" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Python supports a container type called a dictionary." + "# Dictionaries and sets\n", + "\n", + "In addition to lists and tuples, two other container types in Python that is useful to be aware of are _dictionaries_ and _sets_." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "This is also known as an \"associative array\", \"map\" or \"hash\" in other languages." + "## Dictionaries\n", + "\n", + "Python has built-in support for a `dict` container type (short for _dictionary_), with similar types sometimes known as an _associative array_, _map_ or _hash (table)_ in other languages." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "In a list, we use a number to look up an element:" + "In a list, we use an integer index to look up an element, and we can think of lists as maps from integer indices to the corresponding list element:" ] }, { @@ -41,7 +31,7 @@ "metadata": {}, "outputs": [], "source": [ - "names = \"Martin Luther King\".split(\" \")\n", + "names = [\"Martin\", \"Luther\", \"King\"]\n", "names[1]" ] }, @@ -49,7 +39,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In a dictionary, we look up an element using **another object of our choice**:" + "A dictionary on the other hand allows creating maps in which we look up elements using objects of much more general types, for example strings:" ] }, { @@ -58,7 +48,7 @@ "metadata": {}, "outputs": [], "source": [ - "me = {\"name\": \"James\", \"age\": 39, \"Jobs\": [\"Programmer\", \"Teacher\"]}" + "person = {\"name\": \"James\", \"age\": 39, \"Jobs\": [\"Programmer\", \"Teacher\"]}" ] }, { @@ -67,7 +57,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(me)" + "print(person)" ] }, { @@ -76,7 +66,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(me[\"Jobs\"])" + "print(person[\"Jobs\"])" ] }, { @@ -85,21 +75,21 @@ "metadata": {}, "outputs": [], "source": [ - "print(type(me))" + "print(type(person))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Keys and Values" + "### Keys and values" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The things we can use to look up with are called **keys**:" + "The set of objects we use to look up the elements in a dictionary are called **keys**. The `keys` method of a dictionary can be used to extract the collection of all keys in the dictionary:" ] }, { @@ -108,14 +98,14 @@ "metadata": {}, "outputs": [], "source": [ - "me.keys()" + "person.keys()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The things we can look up are called **values**:" + "The objects associated with they keys in a dictionary (the things we look up) are called **values**. The `values` method of a dictionary returns the collection of all values in the dictionary:" ] }, { @@ -124,14 +114,14 @@ "metadata": {}, "outputs": [], "source": [ - "me.values()" + "person.values()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "When we test for containment on a `dict` we test on the **keys**:" + "Dictionaries also define an `items` method which can be used to access the collection of all key-value pairs in the dictionary:" ] }, { @@ -140,16 +130,14 @@ "metadata": {}, "outputs": [], "source": [ - "\"Jobs\" in me" + "person.items()" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "\"James\" in me" + "A peculiarity of dictionaries in Python is that when we test for _containment_, we test on the key:" ] }, { @@ -158,24 +146,7 @@ "metadata": {}, "outputs": [], "source": [ - "\"James\" in me.values()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Immutable Keys Only" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The way in which dictionaries work is one of the coolest things in computer science:\n", - "the \"hash table\". This is way beyond the scope of this course, but it has a consequence:\n", - "\n", - "You can only use **immutable** things as keys." + "\"Jobs\" in person" ] }, { @@ -184,14 +155,14 @@ "metadata": {}, "outputs": [], "source": [ - "good_match = {(\"Lamb\", \"Mint\"): True, (\"Bacon\", \"Chocolate\"): False}" + "\"James\" in person" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "but:" + "To check for whether a dictionary contains a certain value we therefore need to use the `values` method" ] }, { @@ -200,32 +171,36 @@ "metadata": {}, "outputs": [], "source": [ - "illegal = {[1, 2]: 3}" + "\"James\" in person.values()" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [] + }, "source": [ - "*Supplementary material*: You can start to learn about [the 'hash table'](https://www.youtube.com/watch?v=h2d9b_nEzoA). Though this video is **very** advanced I think it's really interesting!" + "### Missing keys and safe lookup\n", + "\n", + "If we try to look up a key not contained in a dictionary we will get an error:" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "## No guarantee of order" + "x = {\"a\": 1, \"b\": 2}\n", + "print(x[\"a\"])\n", + "print(x[\"fish\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "Another consequence of the way dictionaries work is that there's no guaranteed order among the\n", - "elements:\n", - "\n", - "\n" + "To allow safely looking up keys which might not be defined, dictionaries provide a `get` method which takes a single argument corresponding to the key to lookup and returns the value associated with the key if present in the dictionary, and the special `None` value otherwise" ] }, { @@ -234,23 +209,23 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = {\"0\": 0, \"1\": 1, \"2\": 2, \"3\": 3, \"4\": 4}\n", - "print(my_dict)\n", - "print(my_dict.values())" + "print(x.get(\"a\"))" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ - "## Sets" + "print(x.get(\"fish\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "A set is a `list` which cannot contain the same element twice." + "The `get` method can also be called with an optional second argument which is used inplace of `None` as the default value returned if the key is not present in the dictionary" ] }, { @@ -259,26 +234,21 @@ "metadata": {}, "outputs": [], "source": [ - "university = \"University College London\"\n", - "unique_letters = set(university)" + "x.get(\"fish\", \"tuna\") == \"tuna\"" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "unique_letters" + "### Hashable keys only" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "print(\"\".join(unique_letters))" + "Dictionaries in Python are implemented using a data structure called a [_hash table_](https://en.wikipedia.org/wiki/Hash_table#In_programming_languages). The details of how hash tables work is beyond the scope of this course work, but it has a consequence: only [_hashable_](https://docs.python.org/3/glossary.html#term-hashable) objects can be used as keys in dictionaries. Immutable basic types (such as `int`, `float`, `str`) and immutable containers (such as tuples) _which contain only immutable objects_ are hashable and can be used as dictionaries keys. So for example defining a dictionary with keys which are tuples of strings works:" ] }, { @@ -287,14 +257,14 @@ "metadata": {}, "outputs": [], "source": [ - "\"\".join([\"a\", \"b\", \"c\"])" + "good_match = {(\"Salt\", \"Pepper\"): True, (\"Vinegar\", \"Chocolate\"): False}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "It has no particular order, but is really useful for checking or storing **unique** values." + "but using lists as keys doesn't:" ] }, { @@ -303,34 +273,28 @@ "metadata": {}, "outputs": [], "source": [ - "alist = [1, 2, 3]\n", - "is_unique = len(set(alist)) == len(alist)\n", - "print(is_unique)" + "illegal = {[1, 2]: 3}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Safe Lookup" + "*Supplementary material*: If you wish to learn more about hash tables [this YouTube video](https://www.youtube.com/watch?v=h2d9b_nEzoA) gives a comprehensive (but quite advanced) overview." ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "x = {\"a\": 1, \"b\": 2}" + "## Sets" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "x[\"a\"]" + "A set is a container which cannot contain the same element twice." ] }, { @@ -339,16 +303,18 @@ "metadata": {}, "outputs": [], "source": [ - "x[\"fish\"]" + "university = \"University College London\"\n", + "unique_letters = set(university)\n", + "unique_letters" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "x.get(\"a\")" + "### Ordering\n", + "\n", + "Sets are _unordered_ collections, for example there are no guarantees over the order in which items in the set will be printed:" ] }, { @@ -357,7 +323,16 @@ "metadata": {}, "outputs": [], "source": [ - "x.get(\"fish\")" + "print(unique_letters)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Checking uniqueness\n", + "\n", + "Sets are particular useful for checking or storing **unique** values." ] }, { @@ -366,7 +341,9 @@ "metadata": {}, "outputs": [], "source": [ - "x.get(\"fish\", \"tuna\") == \"tuna\"" + "a_list = [1, 2, 3]\n", + "all_elements_unique = len(set(a_list)) == len(a_list)\n", + "print(all_elements_unique)" ] } ], @@ -389,9 +366,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.3" + "version": "3.9.7" } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 4 }