{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Chapter 1: Python Primer\n",
    "## Exercises\n",
    "### Reinforcement"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.1** Write a short Python function, `is_multiple(n, m)`, that takes two integer values and returns True if n is a multiple of m, that is, n = mi for some integer i, and False otherwise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def is_multiple(n, m):\n",
    "    return n % m == 0\n",
    "\n",
    "(is_multiple(4, 2) == True) and (is_multiple(3, 2) == False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.2** Write a short Python function, `is_even(k)`, that takes an integer value and returns True if k is even, and False otherwise. However, your function cannot use the multiplication, modulo, or division operators."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def is_even(k):\n",
    "    even_digit_strings = ['0', '2', '4', '6', '8']\n",
    "    return str(k)[-1] in even_digit_strings\n",
    "\n",
    "(is_even(102) == True) and (is_even(31) == False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.3** Write a short Python function, `minmax(data)`, that takes a sequence of one or more numbers, and returns the smallest and largest numbers, in the form of a tuple of length two. Do not use the built-in functions min or max in implementing your solution."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def minmax(data):\n",
    "    sorted_data = sorted(data)\n",
    "    return (sorted_data[0], sorted_data[-1])\n",
    "\n",
    "minmax([1, 5, 3]) == (1, 5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.4** Write a short Python function that takes a positive integer n and returns the sum of the squares of all the positive integers smaller than n."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def sum_of_smaller_squares(n):\n",
    "    squares = [x * x for x in range(n)]\n",
    "    return sum(squares)\n",
    "\n",
    "sum_of_smaller_squares(5) == 4 * 4 + 3 * 3 + 2 * 2 + 1 * 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.5** Give a single command that computes the sum from Exercise R-1.4, relying on Python’s comprehension syntax and the built-in sum function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum_of_smaller_squares(211) == sum(x * x for x in range(211))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.6** Write a short Python function that takes a positive integer n and returns the sum of the squares of all the odd positive integers smaller than n."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def smaller_odds_squared_sum(n):\n",
    "    odds_squared = [x * x for x in range(n) if x % 2 != 0]\n",
    "    return sum(odds_squared)\n",
    "\n",
    "smaller_odds_squared_sum(6) == 5 * 5 + 3 * 3 + 1 * 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.7** Give a single command that computes the sum from Exercise R-1.6, relying on Python’s comprehension syntax and the built-in sum function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "smaller_odds_squared_sum(211) == sum(x * x for x in range(211) if x % 2 != 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.8** Python allows negative integers to be used as indices into a sequence, such as a string. If string s has length n, and expression s[k] is used for index −n ≤ k < 0, what is the equivalent index j ≥ 0 such that s[j] references the same element?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = \"foobar\"\n",
    "n = len(s)\n",
    "k = -2\n",
    "j = n + k\n",
    "\n",
    "s[k] == s[j]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.9** What parameters should be sent to the range constructor, to produce a range with values 50, 60, 70, 80?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "params = (50, 81, 10)\n",
    "\n",
    "list(range(*params)) == [50, 60, 70, 80]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.10** What parameters should be sent to the range constructor, to produce a range with values 8, 6, 4, 2, 0, −2, −4, −6, −8?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 77,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "params = (8, -9, -2)\n",
    "\n",
    "list(range(*params)) == [8, 6, 4, 2, 0, -2, -4, -6, -8]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.11** Demonstrate how to use Python’s list comprehension syntax to produce the list [1, 2, 4, 8, 16, 32, 64, 128, 256]."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[2 ** n for n in range(0, 9)] == [1, 2, 4, 8, 16, 32, 64, 128, 256]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**R-1.12** Python’s `random` module includes a function `choice(data)` that returns a random element from a non-empty sequence. The `random` module includes a more basic function `randrange`, with parameterization similar to the built-in range function, that returns a random choice from the given range. Using only the `randrange` function, implement your own version of the `choice` function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "metadata": {},
   "outputs": [],
   "source": [
    "from random import randrange\n",
    "\n",
    "def choice(seq):\n",
    "    i = randrange(len(seq))\n",
    "    return seq[i]"
   ]
  }
 ],
 "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.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}