{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "![header](header.png)\n", "\n", "Python's data structures are highly flexible and easy to use for a variety of tasks. The basic idea of a data structure to store information in an organized fashion for later use. This tutorial and accompanying video aims to give an overview of the kinds of things Python's data structures can be used for, and how they can be efficiently created out of existing data.\n", "\n", "We'll also look at list comprehensions, one of Python's best features.\n", "\n", "# Basic structures\n", "\n", "### Tuple\n", "\n", "A tuple is a straightforward way of bundling together a few pieces of related information into an ordered sequence. There is, in general, no expectation that the elements of a tuple be data of the same type. An inventory of products may, for example, be a list of two-element tuples each containing an item (string) and its price (float or integer).\n", "\n", "There are 3 main ways to create a tuple. We detail two in this section -- the final will be explained later. The first is the so called \"literal\" creation of a tuple. In this case, we use round brackets to simply group the information, separated by commas:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a_tuple = (\"hello\", 12345)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The elements of a tuple are accessed by index, starting with the first element indexed as 0:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'hello'" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(a_tuple[0])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The other way to create a tuple is with the tuple() built-in function, which will attempt to force another structure to take on the structure of a tuple. Any data ordered sequentially, such as a list or string, is an easy candidate. For instance, we can transform a string into a tuple, each containg a single character like so:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "('h', 'e', 'l', 'l', 'o')" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(tuple(\"hello\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once we have a tuple, it is very easy to assign each element to a variable. The following syntax will \"unpack\" the tuple we created earlier and set each entry to a different variable:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": true }, "outputs": [], "source": [ "word, number = a_tuple" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'hello'" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(word)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "12345" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(number)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another primary use of tuples is in the outputs of functions. A function that returns multiple pieces information is best off returning a tuple containing each item. Then, the function's doc-string (a multi-line comment that appears at the top of the function definition explaining how the function is used) should inform the programmer of what information is returned in the tuple, and in what order. For example, we consider the partition function that can be used on strings. The help() function outputs the function's doc-string:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on method_descriptor:\n", "\n", "partition(...)\n", " S.partition(sep) -> (head, sep, tail)\n", " \n", " Search for the separator sep in S, and return the part before it,\n", " the separator itself, and the part after it. If the separator is not\n", " found, return S and two empty strings.\n", "\n" ] } ], "source": [ "help(str.partition)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It may look a little cryptic, but the second line says that the partition function takes a separator character, here called \"sep\", as its argument, and the output is a tuple containing three pieces of information. Here is an example. Compare the input and output and compare with the doc-string." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "('Cat', ' | ', 'Dog')" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(\"Cat | Dog\".partition(\" | \"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using the previous technique of unpacking, it is very easy to assign each piece of this output to different variables:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": true }, "outputs": [], "source": [ "before, middle, after = \"Cat | Dog\".partition(\" | \")" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Cat'" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(before)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Dog'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print(after)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Tuples are an example of an immutable data type. This means that, once created, they cannot be modified. You cannot add or change an entry in a tuple. If you need a tuple to \"change\", then what you must really do is create a new tuple and assign it to the same variable. For instance, let's say I have a pair of numbers (coordinates, say) and wish to add one to each of them. What I must really do is create a new tuple, using the old tuple's information in the process. Example:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(6, 4)\n" ] } ], "source": [ "coordinates = (5, 3)\n", "# now want new coordinates\n", "coordinates = (coordinates[0] + 1, coordinates[1] + 1)\n", "print(coordinates)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### List\n", "\n", "Lists are the workhorse structure of Python. Their use case should be pretty intuitive -- you want to make a list of things. While both are order sequentially, they differ from tuples in several important ways. The first is that there is the expectation that the items in the list are all of the same kind. To consider a real world example, imagine you are looking at your receipt after buying groceries. It is perfectly sensible that our receipt is a list of triples (item, quantity, price). However, we would find it incongruous and possibly incomprehensible if items, quantities, and prices were given as separate items in the list! Second, lists are highly dynamic objects. Their entries can be modified, and they can be extended or reduced on the fly. We say they are \"mutable\". Lists have many functions built into them to facilitate these mutations, and we'll showcase some of the more common ones here. Firstly though, we note that creating a list is very similar to creating a tuple. We have 3 methods for doing it, very similar to the tuple, but using square brackets:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a_list = [\"One\", \"Two\", \"Three\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Also, we have the built-in list() function, which will attempt to turn another data structure into a list. For example, a list can be built from a tuple:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Ball', 'Cassidy']" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a_terrible_pair = (\"Ball\", \"Cassidy\") # this is a tuple\n", "print(list( a_terrible_pair )) # this is a list!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is very common to loop over the elements of the list, performing an operation on each element. In the loop syntax, we give each element a temporary name while we work on it. Suppose we wish to print each item in lowercase:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "one\n", "two\n", "three\n" ] } ], "source": [ "for number in a_list: # number is the temporary name given to each item as we work on it\n", " print(number.lower())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One created, the entries in a list can be modified by simply reassigning that entry using the index:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['One', 'Zwei', 'Three']\n" ] } ], "source": [ "a_list[1] = \"Zwei\"\n", "print(a_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A very common task is to add entries to the end of the list. We can do this using the append() function that lists can perform. It is worth noting, however, that append() is an efficient solution to an inherently costly operation. When you create a list, the program allocates a certain amount of memory to the list; using the append() method may require the program to allocate more memory to the list, which may involve reorganizing other allocated memory. This increases computing time. Therefore, if it is at all possible, it is best to build your list all in one go, rather than construct it by repeated use of append(). Of course, this is not always possible. Using append() is simple:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['One', 'Zwei', 'Three', 'Four']\n" ] } ], "source": [ "a_list.append(\"Four\")\n", "print(a_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As well as appending, which always adds the new entry to the end of the list, the insert() function takes as its first argument a position in which to add the new entry:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['Zero', 'One', 'Zwei', 'Three', 'Four']\n" ] } ], "source": [ "a_list.insert(0, \"Zero\")\n", "print(a_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The syntax for deleting a list element is a bit different. We write it like this:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['One', 'Zwei', 'Three', 'Four']\n" ] } ], "source": [ "del a_list[0]\n", "print(a_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The final list operation I'd like to show here is pop(). Pop takes an index as its argument, and outputs the element that index refers to. However, it then deletes the element from the list. In this way, we can think of a list as a container, and when we \"pop\" an item from the list, we take it out of the container to do something with it. From our list, we have:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "THREE\n", "['One', 'Zwei', 'Four']\n" ] } ], "source": [ "an_item = a_list.pop(2)\n", "print(an_item.upper())\n", "print(a_list)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using pop() with no argument performs this operation on the last element of the list. This leads to a certain kind of algorithm \"first in, last out\". Conceive of the list as a pile of cards. You can add a card to the top of the stack, or remove the top card. Therefore, the card added first, will be the last card to be retreived.\n", "\n", "Let's do an example of this kind of algorithm. Mathematical expressions often use brackets to inform us of the correct order to perform the operations. Suppose we want our program to take a mathematical expression containing brackets, and check that every opening bracket has a corresponding closing bracket, and vice versa. The following code will do this very task:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n" ] } ], "source": [ "def check_brackets(expression):\n", " bracket_list = []\n", " for character in expression:\n", " if character == \"(\":\n", " bracket_list.append(character) #add opening brackets to the end of the list\n", " if character == \")\":\n", " if len(bracket_list) == 0: \n", " # the list is empty, so there must be no corresponding opening bracket!\n", " return False\n", " else:\n", " # if there's matching opening bracket, remove it from the list!\n", " bracket_list.pop()\n", " \n", " # returns True only if bracket_list is empty at the end (all brackets were matched)\n", " return len(bracket_list) == 0 \n", " \n", "\n", "print(check_brackets(\"5 * (6 + (4 - (5 * 6)))\"))\n", " " ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n" ] } ], "source": [ "print(check_brackets(\"5 * 5 + ((3+4)\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A 2d grid of values can be represented as a list of lists, and values can be looked up by using two indices. A chessboard for a chess game could have the following representation:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "bP\n" ] } ], "source": [ "board = [\n", " [\"bR\", \"bN\", \"bB\", \"bQ\", \"bK\", \"bB\", \"bN\", \"bR\"],\n", " [\"bP\", \"bP\", \"bP\", \"bP\", \"bP\", \"bP\", \"bP\", \"bP\"],\n", " [ \"\" , \"\" , \"\" , \"\" , \"\" , \"\" , \"\" , \"\" ],\n", " [ \"\" , \"\" , \"\" , \"\" , \"\" , \"\" , \"\" , \"\" ],\n", " [ \"\" , \"\" , \"\" , \"\" , \"\" , \"\" , \"\" , \"\" ],\n", " [ \"\" , \"\" , \"\" , \"\" , \"\" , \"\" , \"\" , \"\" ],\n", " [\"wP\", \"wP\", \"wP\", \"wP\", \"wP\", \"wP\", \"wP\", \"wP\"],\n", " [\"wR\", \"wN\", \"wB\", \"wQ\", \"wK\", \"wB\", \"wN\", \"wR\"]]\n", "\n", "# look up what piece is in a square\n", "print(board[1][3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dictionaries\n", "\n", "Dictionaries are one of the nicest structures in Python. With our previous structures, we could only retreive elements by index -- that is, by the order in which they appear. However, it is very common that the order is not important to us, and we wish to use a word or other identifier to retreive the item from the structure. This is where dictionaries come in. A dictionary is a \"key-value pair\" -- the key is the word (or other identifier) we use to obtain the value. To create a dictionary, we use curly braces. For example:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Berlin\n" ] } ], "source": [ "capital_cities = {\"UK\": \"London\",\n", " \"India\": \"New Delhi\",\n", " \"Germany\": \"Berlin\"}\n", "print(capital_cities[\"Germany\"])" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "London\n" ] } ], "source": [ "beekeeper = {\"Name\": \"Sam\", \"Country\": \"UK\"}\n", "\n", "print(capital_cities[beekeeper[\"Country\"]]) # briefly ponder what this line does" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Keys must be immutable -- objects that cannot be changed. Strings and numbers are good examples of immutable data types. Values can be anything you like. Strings, numbers, lists, even functions! Adding an item to a dictionary is as simple as this:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": true }, "outputs": [], "source": [ "capital_cities[\"Russia\"] = \"Moscow\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dictionaries can be looped over just like lists, but it is usually less clear in what order the items will be looped over, so make sure what you are doing doesn't depend too heavily on the order the operations are performed:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "UK\n", "India\n", "Germany\n", "Russia\n" ] } ], "source": [ "for country in capital_cities:\n", " print(country)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Deleting an item from a dictionary is akin to doing the same for a list:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": true }, "outputs": [], "source": [ "del capital_cities[\"UK\"]" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'India': 'New Delhi', 'Germany': 'Berlin', 'Russia': 'Moscow'}\n" ] } ], "source": [ "print(capital_cities)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, when do we use a dictionary? A key feature of dictionaries is that they allow us to assign words to other objects. This sounds remeniscent of variables, with which we are already very familiar. The difference is that variables are something created by the programmer to appear in the source code. The keys of a dictionary can be created by the program itself as it is running. Suppose your program is running and creating lots of new data, and you want to assign names to the different bits of data you are creating as the program is running. The program cannot create a new variable. But it can put the data into a dictionary and give it a key!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exercises with data structures\n", "\n", "1. Create a list of 4 tuples, each being a pair containing a year and an event from world history that happened in that year.\n", "2. Use the dict() function on the list from exercise 1. Note how this is similar to the tuple() and list() functions. Give the dictionary a name like temp\n", "3. Create a for-loop that prints the items in the dictionary created in problem 2. Notice how this only prints the keys of the dictionary. Now loop over temp.values() instead of temp, and see what happens. What happens if you loop over temp.items()? What data structures does .items() return?\n", "4. (challenge) Modify the check_brackets() code above so that it checks the validity of expressions containing a combination of round, square and curly brackets. Hint: Create a dictionary that associates each kind of opening bracket to its appropriate closing bracket (e.g [ to ]).\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comprehensions\n", "\n", "Now we get to something interesting and very useful. So far, we have been constructing tuples, lists and dictionaries by specifying the items individually. This is all very well, but for large structures, it could take forever! A comprehension is a line of code that specifies how to create a structure by describing the objects in it, rather than stating each one explicitly. We will focus here on list comprehensions, but the syntax is very similar for the other structures.\n", "\n", "Suppose we wish to create a list containing the numbers 0 to 99. A naive way to achieve this task might be:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": true }, "outputs": [], "source": [ "numbers = []\n", "for x in range(100):\n", " numbers.append(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As mentioned above, this repeated use of append() is slow -- it would be faster to create the list containing all the numbers at once, rather than constantly modifying the size of the list. This is where list comprehensions come in. The correct syntax, which we will break down in just a moment is:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": true }, "outputs": [], "source": [ "numbers = [x for x in range(100)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Both of these snippets achieve the same task, but one is shorter, clearer, and faster. Let's take a quick look at the syntax. Note first that we still use square brackets to create the list (if we wanted to use a tuple comprehension, we'd use round brackets). Now, what is this \"x for x\" business? Look first at the latter part of the syntax. It should look exactly like the header of a for-loop for x in range(100). The first x is any expression that should be evaluated for each x before putting the result into the list. In this case, an example really does speak a thousand words:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801]\n" ] } ], "source": [ "numbers = [x**2 for x in range(100)]\n", "print(numbers)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Such an elegant way to construct the list. We have squared each number before adding it to the list. The expression to evaluate can be pretty much anything! For example, we create a list here of tuples containing each number, and whether or not it is prime:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def is_prime(n):\n", " '''basic function to determine if a number is prime'''\n", " if n < 2:\n", " return False\n", " for i in range(2, int(n**(0.5)+1)):\n", " if n % i == 0:\n", " return False\n", " return True\n", "\n", "prime_list = [(p, is_prime(p)) for p in range(20)] # here's the list comprehension!" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(0, False)\n", "(1, False)\n", "(2, True)\n", "(3, True)\n", "(4, False)\n", "(5, True)\n", "(6, False)\n", "(7, True)\n", "(8, False)\n", "(9, False)\n", "(10, False)\n", "(11, True)\n", "(12, False)\n", "(13, True)\n", "(14, False)\n", "(15, False)\n", "(16, False)\n", "(17, True)\n", "(18, False)\n", "(19, True)\n" ] } ], "source": [ "# Now let's view the list\n", "for pair in prime_list:\n", " print(pair)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A list comprehension can also contain if clauses. We could create a list of the prime numbers less than 1000 with the following code:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]\n" ] } ], "source": [ "prime_list = [p for p in range(1000) if is_prime(p)]\n", "print(prime_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This just about covers the power of list comprehensions. Of course, these have only been toy examples, creating lists of numbers with various properties. List comprehensions can be used to construct all kinds of lists. In our demonstration video today, we use list comprehensions to solve a problem that involves extracting data from a file and storing that data in a list.\n", "\n", "It is potentially useful when you are just beginning Python, to work always with the Data Structures page from the manual open https://docs.python.org/3/tutorial/datastructures.html. A large amount of what we do when programming is organizing and retrieving data in structures, so having a reference to all the basic tasks Python can do with its structures is extremely useful!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercises with comprehensions\n", "\n", "1. Create a list containg the first 10 numbers in the 3 times table, using a comprehension.\n", "2. Now create a list of 10 lists, with the $k$th list being the first 10 numbers of the $k$ times table, using a list comprehension within a list comprehension (\"nested\").\n", "3. Head over to https://docs.python.org/3/, the website that contains Python's instruction manual. It's enormous, but knowing your way around it is extremely important for your development as a Python programmer. Try to find the section that explains how to make a dictionary comprehension, and try it out yourself." ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## Example video\n", "\n", "In the following example video, we make use of tuples, dictionaries, and list comprehensions to solve a problem." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "image/jpeg": "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\nREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERA\nREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQERE\nBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERARE\nQEREBERAREQEREBERAREQEREBERAREQEREH/2Q==\n", "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import YouTubeVideo\n", "YouTubeVideo(\"TXiTmmlKmKY\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Footnote to the video\n", "\n", "In the video, we implement a counting dictionary. Python's standard library includes an easier and more powerful way to produce a counting dictionary:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Counter({'B': 2, 'A': 1, 'C': 1})\n" ] } ], "source": [ "from collections import Counter\n", "\n", "a_list = ['A', 'B', 'B', 'C']\n", "count = Counter(a_list)\n", "print(count)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Most common name is [('John', 60)]\n" ] } ], "source": [ "# Hence the same problem from the video can be solved like this:\n", "\n", "with open(\"Directory.txt\") as f:\n", " namecount = Counter([line.partition(\"\\t\")[0] for line in f])\n", "\n", "print(\"Most common name is\", namecount.most_common(1))\n", "# dictionaries provided by Counter come with a function called most_common" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This dictionary comes equipped with some additional features (exactly how this works will be explained in the Object Oriented Programming articles), but the counting algorithm is virtually the same as ours, and seeing algorithms like this is good for the soul of any programmer. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Practice Makes Perfect\n", "\n", "Now equipped with a basic knowledge of functions, data structures, mathematical operations and flow control, you are pretty much ready to start using Python to try to solve simple problems. It's now up to you to practice. Not sure about something? Python's documentation and the excellent programming question and answer website stackoverflow.com will almost certainly have the solution.\n", "\n", "Not sure where to begin practising? Here's some recommendations:\n", "\n", "1) Come up with a simple project of your own to solve.\n", "\n", "2) checkio.org is a fantastic website with an enormous selection of Python programming challenges. The objective of each challenge is to write a function in the browser window that completes a certain task, and then the website itself will test if your function really does meet the required criteria. Once you've solved it you can read other people's solutions to get tips on how to do it better.\n", "\n", "3) If you enjoy a little mathematics, projecteuler.net is a website that provides mathematical problems that are best solved with the aid of a computer and a programming language such as Python. There are hundreds, and they range from very easy (beginning with a variation on Fizzbuzz!) to obscenely difficult." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.1" } }, "nbformat": 4, "nbformat_minor": 1 }