{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# For-Loops and List Comprehensions\n", "\n", "- [Download the lecture notes](https://philchodrow.github.io/PIC16A/content/basics/for_loops_and_comprehensions.ipynb). " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## For Loops\n", "\n", "For-loops are an important *control-flow* construct -- they allow you to repeatedly perform batches of similar operations. A for-loops needs an iterable to loop over; lists and their cousins are the most common iterables for this purpose. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 0\n", "1 1\n", "2 3\n", "3 6\n", "4 10\n", "5 15\n" ] } ], "source": [ "# sum the integers from 0 to 5\n", "j = 0\n", "for i in [0, 1, 2, 3, 4, 5]:\n", " j += i\n", " print(i,j)\n", "# ---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A few points about this example. \n", "\n", "- The `in` keyword is used to specify the iterable over which we are looping. \n", "- The colon `:` begins the *body* of the loop. \n", "- **Indentation matters:** the same example would throw a syntax error if we omitted the indentation. \n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "ename": "IndentationError", "evalue": "expected an indented block (, line 4)", "output_type": "error", "traceback": [ "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m4\u001b[0m\n\u001b[0;31m j += i\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mIndentationError\u001b[0m\u001b[0;31m:\u001b[0m expected an indented block\n" ] } ], "source": [ "# sum the integers from 0 to 5\n", "j = 0\n", "for i in [0, 1, 2, 3, 4, 5]:\n", "j += i\n", "print(i,j)\n", "# ---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The case of looping over integers up to `n` is so common that there is a dedicated function for achieving exactly this behavior: the `range()` function. To count from `0` to `n` inclusive, loop over `range(n+1)`:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "2\n", "3\n", "4\n", "5\n" ] } ], "source": [ "for i in range(6):\n", " print(i)\n", "# ---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Iterating over Strings" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Strings are also iterables: " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "t\n", "o\n", " \n", "b\n", "o\n", "l\n", "d\n", "l\n", "y\n", " \n", "g\n", "o\n" ] } ], "source": [ "for l in \"to boldly go\":\n", " print(l)\n", "# ---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A verbose way to achieve the same result, which is sometimes useful: " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "t\n", "o\n", " \n", "b\n", "o\n", "l\n", "d\n", "l\n", "y\n", " \n", "g\n", "o\n" ] } ], "source": [ "s = \"to boldly go\"\n", "for i in range(len(s)):\n", " print(s[i])\n", "# ---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also use `str.split()` to loop over entire words: " ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "to\n", "boldly\n", "go\n" ] } ], "source": [ "for w in \"to boldly go\".split():\n", " print(w)\n", "# ---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Indexing Variable\n", "\n", "In each case, the indexing variable is assigned in global scope (i.e. outside the context of the for loop), and can be used later if desired. " ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(11, 'o', 'go')" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "i, l, w" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The indexing variable is reassigned with each iteration of the loop. This can occasionally be a source of mistakes. For example, take a moment to consider the following code: what is the value of `i` at the end of the loop?" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "i = 1\n", "for i in range(10):\n", " i = i*2" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "18" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "i" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Compare to: " ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "j = 1\n", "for i in range(10):\n", " j = j*2" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1024" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "j" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating Lists with For-Loops\n", "\n", "A versatile way to construct lists is by first initiating an empty list, and then incrementally adding to it. Suppose I wanted to make a list of all integer squares up to 100. Here's a way to do this with a *for loop*:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "squares = [] # an empty list\n", "for i in range(1, 11): # i ranges from 1 to 10\n", " squares.append(i**2) # add i**2 to the end of squares\n", "\n", "squares" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also create a list of the lengths of words in a string: " ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 6, 2]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s = \"to boldly go\"\n", "\n", "word_lengths = []\n", "for word in s.split():\n", " the_length = len(word)\n", " word_lengths.append(the_length)\n", "\n", "word_lengths" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### List Comprehensions\n", "\n", "A much more compact and readable way to construct lists is provided by *list comprehensions.* List comprehensions are inspired by \"set-builder\" notation in mathematics. For example, we might write the `squares` list from above as \n", "\n", "$$\\{i^2 \\;|\\; 1 \\leq i \\leq 10\\}$$\n", "\n", "List comprehensions allow us to write very similar Python code, using the `for` keyword again. " ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "squares = [i**2 for i in range(1, 11)]\n", "squares " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We were able to condense the three lines of code from our for-loop into just one, readable line. Similarly, " ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 6, 2]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "word_lengths = [len(word) for word in s.split()]\n", "word_lengths" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also write *conditional* comprehensions to construct even more complex lists: " ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[4, 16, 36, 64, 100, 144, 196, 256, 324, 400]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "even_squares = [i**2 for i in range(1,21) if i % 2 == 0]\n", "even_squares" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can iterate over multiple indexing variables: " ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[4, 5, 6, 8, 10, 12, 12, 15, 18]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "products = [i*j for i in [1,2,3] for j in [4, 5, 6]]\n", "products" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also easily construct lists of lists: " ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[4, 8, 12], [5, 10, 15], [6, 12, 18]]" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "products2 = [[i*j for i in [1,2,3]] for j in [4, 5, 6]]\n", "products2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Comprehensions are a powerful tool which should often be preferred to for-loops when constructing lists. " ] } ], "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.8.3" } }, "nbformat": 4, "nbformat_minor": 4 }