From c1ad5d8b961f9231c12125a317c4b9ad984f5b8a Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Thu, 12 Mar 2020 00:53:56 +0100 Subject: [PATCH] Add new exercises set for chapter 04 --- 04_iteration_00_lecture.ipynb | 34 ++- 04_iteration_03_exercises.ipynb | 402 ++++++++++++++++++++++++++++++++ 2 files changed, 430 insertions(+), 6 deletions(-) create mode 100644 04_iteration_03_exercises.ipynb diff --git a/04_iteration_00_lecture.ipynb b/04_iteration_00_lecture.ipynb index 1a72c7b..fb89130 100644 --- a/04_iteration_00_lecture.ipynb +++ b/04_iteration_00_lecture.ipynb @@ -37,6 +37,28 @@ "## Recursion" ] }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "A popular joke among programmers by an unknown author goes like this (cf., [discussion](https://www.quora.com/What-does-the-phrase-in-order-to-understand-recursion-you-must-first-understand-recursion-mean-to-you)):" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "-" + } + }, + "source": [ + "> \"In order to understand **recursion**, you must first understand **recursion**.\"" + ] + }, { "cell_type": "markdown", "metadata": { @@ -859,7 +881,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "37.3 µs ± 1.25 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + "35.2 µs ± 971 ns per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], @@ -881,7 +903,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "11.4 ms ± 144 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + "11.2 ms ± 81.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], @@ -903,7 +925,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "3.63 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + "3.67 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" ] } ], @@ -925,7 +947,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "5.93 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + "5.94 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" ] } ], @@ -4543,7 +4565,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "5.24 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" + "5.22 s ± 0 ns per loop (mean ± std. dev. of 1 run, 1 loop each)\n" ] } ], @@ -4824,7 +4846,7 @@ } }, "source": [ - "The `for` statement, on the contrary, makes the actual business logic more apparent by stripping all the **[boilerplate code](https://en.wikipedia.org/wiki/Boilerplate_code)** away." + "The `for` statement, on the contrary, makes the actual business logic more apparent by stripping all the **[boilerplate code](https://en.wikipedia.org/wiki/Boilerplate_code)** away. The variable that is automatically set by Python in each iteration of the loop (i.e., `element` in the example) is called the **target variable**." ] }, { diff --git a/04_iteration_03_exercises.ipynb b/04_iteration_03_exercises.ipynb new file mode 100644 index 0000000..da32407 --- /dev/null +++ b/04_iteration_03_exercises.ipynb @@ -0,0 +1,402 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "# Chapter 4: Recursion & Looping" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Coding Exercises" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Read [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) of the book. Then, work through the exercises below. The `...` indicate where you need to fill in your answers. You should not need to create any additional code cells." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Throwing the Dice" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this exercise, you will model the throwing of dice within the context of a guessing game similar to the one shown in the \"*Example: Guessing a Coin Toss*\" section in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Example:-Guessing-a-Coin-Toss).\n", + "\n", + "As the game involves randomness, we import the [random](https://docs.python.org/3/library/random.html) module from the [standard library](https://docs.python.org/3/library/index.html). To follow best practices, we set the random seed as well." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "random.seed(42)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A die has six sides that we labeled with integers `1` to `6` in this exercise. For a fair die, the probability for each side is the same.\n", + "\n", + "**Q1**: Model a `fair_die` as a `list` object!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fair_die = ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q2**: What function from the [random](https://docs.python.org/3/library/random.html) module that we have seen already is useful for modeling a single throw of the `fair_die`? Write a simple expression (i.e., one function call) that draws one of the equally likely sides! Execute the cell a couple of times to \"see\" the probability distribution!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's check if the `fair_die` is indeed fair. To do so, we create a little numerical experiment and throw the `fair_die` `100000` times. We track the six different outcomes in a `list` object called `throws` that we initialize with all `0`s for each outcome.\n", + "\n", + "**Q3**: Complete the `for`-loop below such that it runs `100000` times! In the body, use your answer to **Q2** to simulate a single throw of the `fair_die` and update the corresponding count in `throws`!\n", + "\n", + "Hints: You need to use the indexing operator `[]` and calculate an `index` in each iteration of the loop. Do do not actually need the target variable provided by the `for`-loop and may want to indicate that with an underscore `_`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "throws = [0, 0, 0, 0, 0, 0]\n", + "\n", + "for ... in ...:\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + "throws" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`throws` contains the simulation results as absolute counts.\n", + "\n", + "**Q4**: Complete the `for`-loop below to convert the counts in `throws` to relative frequencies stored in a `list` called `frequencies`! Round the frequencies to three decimals with the built-in [round()](https://docs.python.org/3/library/functions.html#round) function!\n", + "\n", + "Hints: Initialize `frequencies` just as `throws` above. How many iterations does the `for`-loop have? `6` or `100000`? You may want to obtain an `index` variable with the [enumerate()](https://docs.python.org/3/library/functions.html#enumerate) built-in." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "frequencies = [0, 0, 0, 0, 0, 0]\n", + "\n", + "for ... in ...:\n", + " ...\n", + "\n", + "frequencies" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q5**: How could we adapt the `list` object used above to model an `unfair_die` where `1` is as likely as `2`, `2` is twice as likely as `3`, and `3` is twice as likely as `4`, `5`, or `6`, who are all equally likely?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "unfair_die = ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q6**: Copy your solution to **Q2** for the `unfair_die`! Execute the cell a couple of times to \"see\" the probability distribution!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q7**: Copy and adapt your solutions to **Q3** and **Q4** to calculate the `frequencies` for the `unfair_die`!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "throws = [0, 0, 0, 0, 0, 0]\n", + "frequencies = [0, 0, 0, 0, 0, 0]\n", + "\n", + "for ... in ...:\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + "for ... in ...:\n", + " ...\n", + "\n", + "frequencies" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q8**: The built-in [input()](https://docs.python.org/3/library/functions.html#input) allows us to ask the user to enter a `guess`. What is the data type of the object returned by [input()](https://docs.python.org/3/library/functions.html#input)? Assume the user enters the `guess` as a number (i.e., \"1\", \"2\", ...) and not as a text (e.g., \"one\")." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "guess = input(\"Guess the side of the die: \")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "guess" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q9**: Use a built-in constructor to cast `guess` as an `int` object!\n", + "\n", + "Hint: Simply wrap `guess` or `input(\"Guess the side of the die: \")` with the constructor you choose." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q10**: What type of error is raised if `guess` cannot be cast as an `int` object?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q11**: Write a `try` statement that catches the type of error (i.e., your answer to **Q10**) raised if the user's input cannot be cast as an `int` object! Print out some nice error message notifying the user of the bad input!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " ...\n", + "except ...:\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q12**: Write a function `get_guess()` that takes a user's input and checks if it is a valid side of the die! The function should *return* either an `int` object between `1` and `6` or `None` if the user enters something invalid.\n", + "\n", + "Hints: You may want to re-use the `try` statement from **Q11**. Instead of printing out an error message, you can also `return` directly from the `except`-clause (i.e., early exit) with `None`. So, the user can make *two* kinds of input errors and maybe you want to model that with two *distinct* `return None` statements. Also, you may want to allow the user to enter leading and trailing whitespace that gets removed without an error message." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_guess():\n", + " \"\"\"Process the user's input.\n", + " \n", + " Returns:\n", + " guess (int / NoneType): either 1, 2, 3, 4, 5 or 6\n", + " if the input can be parsed and None otherwise\n", + " \"\"\"\n", + " ...\n", + "\n", + " # Check if the user entered an integer.\n", + " ...\n", + " ...\n", + " ...\n", + " ...\n", + "\n", + " # Check if the user entered a valid side.\n", + " ...\n", + " ...\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q13** Test your function for all *three* cases!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "get_guess()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Q14**: Write an *indefinite* loop where in each iteration a `fair_die` is thrown and the user makes a guess! Print out an error message if the user does not enter something that can be understood as a number between `1` and `6`! The game should continue until the user makes a correct guess." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "...\n", + "...\n", + "...\n", + "\n", + "...\n", + "...\n", + "...\n", + "...\n", + "...\n", + "...\n", + "..." + ] + } + ], + "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.7.4" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": true, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": false, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}