diff --git a/Exercises/Intro2Python/Module1-DataTypes.ipynb b/Exercises/Intro2Python/Module1-DataTypes.ipynb new file mode 100644 index 0000000..fc104f6 --- /dev/null +++ b/Exercises/Intro2Python/Module1-DataTypes.ipynb @@ -0,0 +1,1129 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 1. Data Types\n", + "\n", + "## Code comments\n", + "In order to explain the code, comments in Python can be made by preceding a line with a hashtag `#`. Everything on that particular line will then not be interpreted as part of the code:\n", + "\n", + "```python\n", + "# This is a comment and will not be interpreted as code\n", + "```\n", + "\n", + "## Data Types\n", + "The basic data types in Python are illustrated below." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Integers (`int`)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Integer a: 2\n", + "Integer b: 239\n" + ] + } + ], + "source": [ + "# Integers, in Python, integers are of arbitrary precision and can grow as large as the memory allows.\n", + "a = 2 #assigning an integer value to variable 'a'\n", + "b = 239 #assigning another integer value to variable 'b'\n", + "\n", + "# We can print the values of these integers\n", + "print(\"Integer a:\", a)\n", + "print(\"Integer b:\", b)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "239" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b # print a simple message to the console" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a # print a simple message to the console" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Floating point numbers (`float`)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Float c: 2.1\n", + "Float d: 239.0\n" + ] + } + ], + "source": [ + "# Floats, a float is a number that has a decimal place.\n", + "c = 2.1 #assigning a float value to variable 'c'\n", + "d = 239.0 #assigning another float value to variable 'd'\n", + "\n", + "# We can print the values of these floats\n", + "print(\"Float c:\", c)\n", + "print(\"Float d:\", d)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Strings (`str`)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello world!\n", + "This is my text\n", + "My first message is: Hello world! and my second message is: This is my text\n" + ] + } + ], + "source": [ + "# Strings, strings are sequences of characters enclosed in quotes.\n", + "e = 'Hello world!' #string variable\n", + "my_text = 'This is my text' #another string variable\n", + "\n", + "print(e)\n", + "print(my_text)\n", + "print(f\"My first message is: {e} and my second message is: {my_text}\") #this is an f-string" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that strings are ***immutable***, which means that they can't be changed after creation. They can be copied, then manipulated and thereafter saved into a new variable though." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "H\n" + ] + }, + { + "ename": "TypeError", + "evalue": "'str' object does not support item assignment", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[6], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m#try to change the strings\u001b[39;00m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(e[\u001b[38;5;241m0\u001b[39m]) \u001b[38;5;66;03m#Call the first character of the e string from above\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m \u001b[43me\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mh\u001b[39m\u001b[38;5;124m'\u001b[39m \u001b[38;5;66;03m# This will raise an error because strings are immutable\u001b[39;00m\n", + "\u001b[0;31mTypeError\u001b[0m: 'str' object does not support item assignment" + ] + } + ], + "source": [ + "#try to change the strings\n", + "print(e[0]) #Call the first character of the e string from above\n", + "e[0] = 'h' # This will raise an error because strings are immutable" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Boolean (`bool`)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Boolean x: True\n", + "Boolean y: False\n" + ] + } + ], + "source": [ + "x = True #assigning a boolean value to variable 'x', notice how the text color changes. Also, the first letter is capitalized.\n", + "y = False #assigning another boolean value to variable 'y', notice the same things as above.\n", + "\n", + "# Print the boolean values\n", + "print(\"Boolean x:\", x)\n", + "print(\"Boolean y:\", y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Calculations with data types" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Standard calculator-like operations\n", + "Most basic operations on integers and floats such as addition, subtraction, multiplication work as one would expect:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "180" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "2 * 9*10" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The data type of variable 'a' is: \n", + " the value is: 8\n", + "The data type of variable 'b' is: \n", + " the value is: 16.0\n" + ] + } + ], + "source": [ + "a = 2*4\n", + "\n", + "#print the data type of variable 'a'\n", + "print(\"The data type of variable 'a' is:\", type(a), \"\\n the value is:\", a) #the \\n adds a new line\n", + "\n", + "b = 2.0 * a\n", + "#print the data type of variable 'b'\n", + "print(f\"The data type of variable 'b' is: {type(b)} \\n the value is: {b}\") #using an f-string" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The data type of variable 'c' is: \n", + " the value is: 0.4\n" + ] + } + ], + "source": [ + "c = 2 / 5\n", + "print(f\"The data type of variable 'c' is: {type(c)} \\n the value is: {c}\") #using an f-string, we divide two integers and get a float" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The data type of variable 'd' is: \n", + " the value is: 10.5\n" + ] + } + ], + "source": [ + "d = 3.1 + 7.4\n", + "print(f\"The data type of variable 'd' is: {type(d)} \\n the value is: {d}\") #using an f-string" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## We can do this with the assigned variables too" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Sum: 15\n", + "Difference: 5\n", + "Product: 50\n", + "Quotient: 2.0\n" + ] + } + ], + "source": [ + "#assign values to variables\n", + "a = 10\n", + "b = 5\n", + "\n", + "#perform arithmetic operations using the variables\n", + "sum_result = a + b\n", + "diff_result = a - b\n", + "prod_result = a * b\n", + "quot_result = a / b\n", + "\n", + "# Print the results\n", + "print(\"Sum:\", sum_result)\n", + "print(\"Difference:\", diff_result)\n", + "print(\"Product:\", prod_result)\n", + "print(\"Quotient:\", quot_result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exponents \n", + "Exponents are denoted by `**`:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "8" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "2**3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> **Watch Out**: The `^` operator is **not** used for exponentiation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Floor division\n", + "Floor division is denoted by `//`. It returns the integer part of a division result (removes decimals after division):" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Floor division: 3. The data type is \n", + "Division: 3.3333333333333335. The data type is \n" + ] + } + ], + "source": [ + "fd = 10 // 3\n", + "d = 10/3\n", + "\n", + "print(f\"Floor division: {fd}. The data type is {type(fd)}\")\n", + "print(f\"Division: {d}. The data type is {type(d)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Modulo\n", + "Modulo is denoted by `%`. It returns the remainder after a division:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Modulus: 1. The data type is \n" + ] + } + ], + "source": [ + "md = 10 % 3\n", + "print(f\"Modulus: {md}. The data type is {type(md)}\") # gives the remainder of the division. e.g., 10 divided by 3 is 3 with a remainder of 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Operations on strings\n", + "Strings can be **added** (concatenated) by use of the addition operator `+`:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Cool Hydrology'" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "'Cool ' + 'Hydrology' # concatenation of strings, the ' ' adds a space between the two strings" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Multiplication** is also allowed:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'aaaaaaaaaa'" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "'a' * 10 # string repetition, this will repeat the string 'a' three times resulting in 'aaa'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Subtraction** and **division** are not allowed: " + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "unsupported operand type(s) for /: 'str' and 'int'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[23], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43ma\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m/\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m3\u001b[39;49m \u001b[38;5;66;03m# Division results in error, you cannot divide a string by a number\u001b[39;00m\n", + "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for /: 'str' and 'int'" + ] + } + ], + "source": [ + "'a' / 3 # Division results in error, you cannot divide a string by a number" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "unsupported operand type(s) for -: 'str' and 'str'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[24], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43ma\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mb\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m \u001b[38;5;66;03m# Subtraction results in error\u001b[39;00m\n", + "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for -: 'str' and 'str'" + ] + } + ], + "source": [ + "'a' - 'b' # Subtraction results in error" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Printing strings with variables" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There is quite often a need for printing a combination of static text and variables. This could e.g. be to output the result of a computation. Often the best way is to use the so-called **f-strings**. See examples below." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Multiplication: a * b = 2 * 27 = 54\n", + "Division: a / b = 2 / 27 = 0.07407407407407407\n" + ] + } + ], + "source": [ + "# Basic usage of f-strings\n", + "a = 2 #assigning an integer value to variable 'a'\n", + "b = 27 #assigning another integer value to variable 'b'\n", + "print(f'Multiplication: a * b = {a} * {b} = {a*b}') #using f-strings to format output\n", + "print(f'Division: a / b = {a} / {b} = {a/b}') #using f-strings to format output" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Division: a / b = 2 / 27 = 0.07407\n" + ] + } + ], + "source": [ + "# f-strings with formatting for number of decimal places\n", + "print(f'Division: a / b = {a} / {b} = {a/b:.5f}') # The part ':.xf' specfifies 'x' decimals to be printed, in this case 3 decimals" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Both variables and complex computations can be inserted inside the curly brackets to be printed." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Computation insde curly bracket: 316.6808510638298\n" + ] + } + ], + "source": [ + "print(f'Computation insde curly bracket: {122**2 / 47}') #122 squared, then divided by 47" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Function: `len()`\n", + "The `len()` function returns the length of a sequence, e.g. a string:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len('aaa') # returns the length of the string, in this case 3" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "7" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len('a and b') # Spaces are also counted" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Some string methods\n", + "A string object can be interacted with in many ways by so-called ***methods***. Some useful methods are shown below:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "29" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "name = 'Streamflow Monitoring Station' #assigning a string to variable 'name'\n", + "len(name) # returns the length of the string assigned to variable 'name'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `string.replace()`\n", + "Replaces characters inside a string:\n", + "~~~python\n", + "string.replace('old_substring', 'new_substring')\n", + "~~~" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Streamflow Monitoring Location\n", + "Streamflow Monitoring Station\n" + ] + } + ], + "source": [ + "print(name.replace('Station', 'Location'))# replaces 'Station' with 'Location' in the string assigned to variable 'name'\n", + "print(name) # original string remains unchanged because strings are immutable and we did not reassign the modified string back to 'name'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Recall that strings are ***immutable***. They can be copied, manipulated and saved to a new variable. But they can't be changed per se. This concept transfers to other more complex constructs as well." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to save the replacement and retain the name of the variable, we could just reassign it to the same name:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Streamflow Monitoring Location\n" + ] + } + ], + "source": [ + "name = name.replace('Station', 'Location') # reassign the modified string back to 'name'\n", + "print(name) # now the string assigned to 'name' is updated" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Internally, the computer gives this new `name` variable a new id due to the immutability." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `string.endswith()`\n", + "This method might be self explanatory, but returns a ***boolean*** (`True` of `False`) depending on whether or not the strings ends with the specified substring.\n", + "\n", + "~~~python\n", + "string.endswith('substring_to_test_for')\n", + "~~~" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "name.endswith('g')" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "name.endswith('n')" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "name.endswith('ion')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `string.endswith()` functions can be very useful for data processing, especially for column names." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `string.count()`\n", + "Counts the number of occurences of a substring inside a string:\n", + "~~~python\n", + "string.count('substring_to_count')\n", + "~~~\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Streamflow Monitoring Location\n" + ] + }, + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(name)\n", + "name.count('i')" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "name.count('flow')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The match is case sensitive:" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "name.count('t')" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "name.count('T')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Find the length of the following string:\n", + "> ~~~~python\n", + "> s = \"Utah's SNOTEL sites are recording below average snow this year\"\n", + "> ~~~~" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 2\n", + "Test if `s` from above has *\"year\"* as last characters (should return `True` of course)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 3\n", + "Print the following sentence using an `f-string`:\n", + "\n", + "```python\n", + "'There are {insert_length_of_s} SNOTEL sites in Utah.'\n", + "```\n", + "\n", + "Use `s` from above." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 4\n", + "Use the `count()` method to print the number of ***e***'s in the string `s` form above." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 5\n", + "Use the `replace()` method to replace `SNOTEL` with `USGS` in the following string:\n", + "\n", + ">~~~python\n", + "string1 = 'SNOTEL in situ monitoring sites support regional water management activities'\n", + ">~~~\n", + "\n", + "Save the new string in a variable `string2` and print the both sentences, with `string1` above `string2`:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next [Module](./Module2-Conditionals.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "p310env", + "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.10.19" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Table of Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Exercises/Intro2Python/Module2-Conditionals.ipynb b/Exercises/Intro2Python/Module2-Conditionals.ipynb new file mode 100644 index 0000000..a598273 --- /dev/null +++ b/Exercises/Intro2Python/Module2-Conditionals.ipynb @@ -0,0 +1,281 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conditionals and code indendation\n", + "In Python, code blocks are separated by use of indentation. See the defintion of an `if`-statement below:\n", + "\n", + "### Syntax of conditional blocks\n", + " \n", + "```python\n", + "if condition:\n", + " # Code goes here (must be indented!)\n", + " # Otherwise, IndentationError will be thrown\n", + "\n", + "# Code placed here is outside of the if-statement \n", + "```\n", + "\n", + "Where evaluation of `condition` must return a boolean (`True` or `False`).\n", + "\n", + "\n", + "> **Remember:**\n", + "> 1. The `:` ***must*** be present after `condition`.\n", + "> 2. The line immediately after `:` ***must*** be indented. \n", + "> 3. The `if`-statement is ***exited by reverting the indentation*** as shown above.\n", + "\n", + "This is how Python interprets the code as a block. \n", + "\n", + "The same indentation rules are required for all types of code blocks, the `if`-block above is just an example. Examples of other types of code blocks are `for` and `while` loops, functions etc.\n", + "\n", + "All editors will automatically make the indentation upon hitting enter after the `:`, so it doesn't take long to get used to this. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conditional statements - examples\n", + "\n", + "### `if`-statements\n", + "An `if`-statement has the following syntax:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x is larger than 1\n" + ] + } + ], + "source": [ + "x = 2 # Example variable assignment\n", + "if x > 1: # Check if x is greater than 1\n", + " print('x is larger than 1') # Print message if condition is true" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `if` / `else`-statements" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "y is less than or equal to 1\n" + ] + } + ], + "source": [ + "#an if-else statement example. This will execute one block of code if the condition is true, and another block if it is false.\n", + "\n", + "y = 1 # Another example variable assignment, make example where we set the if value to a variable...\n", + "if y > 1: # Check if y is greater than 1\n", + " print('y is larger than 1') # Print message if condition is true\n", + "else:\n", + " print('y is less than or equal to 1') # Print message if condition is false" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `if` / `elif` / `else`" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "z is less than 1\n" + ] + } + ], + "source": [ + "#an if-elif-else statement example. This will check multiple conditions in sequence.\n", + "\n", + "z = 0 # Another example variable assignment\n", + "if z > 1: # Check if z is greater than 1\n", + " print('z is larger than 1') # Print message if condition is true\n", + "elif z < 1: # Check if z is less than 1 using the elif statement\n", + " print('z is less than 1') # Print message if the elif condition is true\n", + "else: # This block executes if none of the above conditions are true\n", + " print('z is equal to 1') # Print message if z is equal to 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An unlimited number of `elif` blocks can be used in between `if` and `else`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 1\n", + "If the string below has more than 100 characters, print *\"String has more than 100 characters\"*, otherwise print *\"String has less than or exactly 100 characters\"*.\n", + "~~~python\n", + "string = 'There are approximately 114 SNOTEL sites in Utah, as a part of the Natural Resouces Conservation Service (NRCS) and ~150 USGS NWIS streamflow monitoring gages.'\n", + "~~~" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 2\n", + "Print the number of space characters in `string` from above. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 3\n", + "Create the variables\n", + "\n", + "```python\n", + "letter1 = 'USGS sites'\n", + "letter2 = 'SNOTEL sites'\n", + "```\n", + "\n", + "Convert this pseudo code to a Python program:\n", + "\n", + "```python\n", + "if there are more occurrences of letter1 than letter2 in string:\n", + " print(\"There are more {insert_letter1} than {insert_letter2} \")\n", + " \n", + "elif there are more occurrences of letter2 than letter1 in string:\n", + " print(\"There are more {insert_letter2} than {insert_letter1} \")\n", + "\n", + "else:\n", + " print(\"There are exactly the same number {insert_letter1} and {insert_letter2}\")\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 4\n", + "Test the program you wrote above with different combinations of letters for the variables `letter1` and `letter2`. \n", + "Implement a print message of the actual number of occurrences." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next [Module](./Module3-DataStructures.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "p310env", + "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.10.19" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Table of Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Exercises/Intro2Python/Module3-DataStructures.ipynb b/Exercises/Intro2Python/Module3-DataStructures.ipynb new file mode 100644 index 0000000..5d8b103 --- /dev/null +++ b/Exercises/Intro2Python/Module3-DataStructures.ipynb @@ -0,0 +1,932 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "# Data Structures\n", + "\n", + "Data structures are constructs that can contain one or more variables. They are containers that can store a lot of data into a single entity.\n", + "\n", + "**Python's four basic data structures are:**\n", + " * Lists\n", + " * Dictionaries\n", + " * Tuples\n", + " * Sets\n", + "\n", + " Note, DataFrames are not a standard part of Python. While DataFrames are often used, they are part of the `Pandas` library.\n", + "\n", + "## Lists \n", + "Lists are defined by square brackets `[]` with elements separated by commas. They can have elements of any data type.\n", + "\n", + "Lists are arguably the most used data structure in Python.\n", + "\n", + "### List syntax \n", + " L = [item_1, item_2, ..., item_n] \n", + "\n", + "### Mutability\n", + "Lists are ***mutable***. They can be changed after creation.\n", + "\n", + "### List examples\n", + "Some examples of lists:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "List a: [10, 20, 30, 40]\n", + "List b: [1, True, 'SNOTEL', 4.3]\n", + "List c: [['Nested', 'lists'], ['are', 'possible']]\n" + ] + } + ], + "source": [ + "# List with integers\n", + "a = [10, 20, 30, 40]\n", + "\n", + "# Multiple data types in the same list\n", + "b = [1, True, 'SNOTEL', 4.3] \n", + "\n", + "# List of lists\n", + "c = [['Nested', 'lists'], ['are', 'possible']] \n", + "\n", + "# Print the lists\n", + "print(\"List a:\", a)\n", + "print(\"List b:\", b)\n", + "print(\"List c:\", c)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dictionaries\n", + "Dictionaries have key/value pairs which are enclosed in curly brackets`{}` or we can call the `dict` function. A value can be fetched by querying the corresponding key. Refering the data via logically named keys instead of list indexes makes the code more readable.\n", + "\n", + "### Dictionary syntax \n", + " \n", + " d = {key1: value1, key2: value2, ..., key_n: value_n} \n", + "\n", + " d = dict(key1= value1, key2 = value2, ..., key_n = value_n) \n", + " \n", + "Note that values can be of any data type like floats, strings etc., but they can also be lists or other data structures.\n", + "\n", + "**Keys must be unique within the dictionary**. Otherwise it would be hard to extract the value by calling out a certain key, see the section about indexing and slicing below.\n", + "\n", + "Keys also must be of an immutable type.\n", + " \n", + "### Mutability\n", + "Dictionaries are ***mutable***. They can be changed after creation.\n", + "\n", + "### Dictionary examples\n", + "Some examples of dictionaries:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Strings as keys and numbers as values\n", + "d1 = {'axial_force': 319.2, 'moment': 74, 'shear': 23} \n", + "d1_dict = dict(axial_force=319.2, moment=74, shear=23)\n", + "\n", + "# Strings as keys and lists as values\n", + "d2 = {'Point1': [1.3, 51, 10.6], 'Point2': [7.1, 11, 6.7]} \n", + "d2_dict = dict(Point1=[1.3, 51, 10.6], Point2=[7.1, 11, 6.7])\n", + "\n", + "# Keys of different types (int and str, don't do this!)\n", + "d3 = {1: True, 'hej': 23} " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "The first two dictionaries above have a certain trend. For `d1` the keys are strings and the values are integers. For `d2` the keys are strings and the values are lists. These are well-structured dictionaries.\n", + "\n", + "However, `d3` has keys that are of mixed types! The first key is an integer and the second is a string. This is totally valid syntax, but not a good idea to do.\n", + "\n", + "As with most stuff in Python the flexibility is very nice, but it can also be confusing to have many different types mixed in the same data structure. To make code more readable, it is often preferred to keep the same trend throughout the dictionary. I.e. all keys are of same type and all values are of the same type as in `d1` and `d2`.\n", + "\n", + "The keys and values can be extracted separately by the methods `dict.keys()` and `dict.values()`:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "d1 keys: dict_keys(['axial_force', 'moment', 'shear'])\n", + "d1_dict keys: dict_keys(['axial_force', 'moment', 'shear'])\n", + "d2 keys: dict_keys(['Point1', 'Point2'])\n", + "d2_dict keys: dict_keys(['Point1', 'Point2'])\n", + "d3 keys: dict_keys([1, 'hej'])\n" + ] + } + ], + "source": [ + "#print the keys in the dictionaries\n", + "print(\"d1 keys:\", d1.keys())\n", + "print(\"d1_dict keys:\", d1_dict.keys())\n", + "print(\"d2 keys:\", d2.keys())\n", + "print(\"d2_dict keys:\", d2_dict.keys())\n", + "print(\"d3 keys:\", d3.keys())\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "d1 values: dict_values([319.2, 74, 23])\n", + "d1_dict values: dict_values([319.2, 74, 23])\n", + "d2 values: dict_values([[1.3, 51, 10.6], [7.1, 11, 6.7]])\n", + "d2_dict values: dict_values([[1.3, 51, 10.6], [7.1, 11, 6.7]])\n", + "d3 values: dict_values([True, 23])\n" + ] + } + ], + "source": [ + "#print the values in the dictionaries\n", + "print(\"d1 values:\", d1.values())\n", + "print(\"d1_dict values:\", d1_dict.values())\n", + "print(\"d2 values:\", d2.values())\n", + "print(\"d2_dict values:\", d2_dict.values())\n", + "print(\"d3 values:\", d3.values())" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "d1 axial_force: 319.2\n", + "d1_dict force: 319.2\n", + "d2 Point1: [1.3, 51, 10.6]\n", + "d2_dict Point1: [1.3, 51, 10.6]\n", + "d3 key 1: True\n" + ] + } + ], + "source": [ + "#Call items in the dictionaries and print them\n", + "print(\"d1 axial_force:\", d1['axial_force'])\n", + "print(\"d1_dict force:\", d1_dict['axial_force'])\n", + "print(\"d2 Point1:\", d2['Point1'])\n", + "print(\"d2_dict Point1:\", d2_dict['Point1'])\n", + "print(\"d3 key 1:\", d3[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tuples\n", + "Tuples are very comparable to lists, but they are defined by parentheses `()`. Most notable difference from lists is that tuples are **immutable**.\n", + "\n", + "### Tuple syntax \n", + " t = (item_1, item_2, ..., item_n) \n", + "\n", + "### Mutability\n", + "Tuples are ***immutable***. They cannot be changed after creation.\n", + "\n", + "### Tuple examples" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# Simple tuple of integers\n", + "t1 = (1, 24, 56) \n", + "\n", + "# Multiple types as tuple elements\n", + "t2 = (1, 1.62, '12', [1, 2 , 3]) #we have an integer, a float, a string, and a list\n", + "\n", + "# Tuple of tuples\n", + "points = ((4, 5), (12, 6), (14, 9)) " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tuple t1: (1, 24, 56)\n", + "Tuple t2: (1, 1.62, '12', [1, 2, 3])\n", + "Tuple points: ((4, 5), (12, 6), (14, 9))\n" + ] + } + ], + "source": [ + "#print the tuples\n", + "print(\"Tuple t1:\", t1)\n", + "print(\"Tuple t2:\", t2)\n", + "print(\"Tuple points:\", points)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "this is the first element of t1: 1\n" + ] + }, + { + "ename": "TypeError", + "evalue": "'tuple' object does not support item assignment", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[8], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m#try to change a tuple element (this will raise an error)\u001b[39;00m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mthis is the first element of t1:\u001b[39m\u001b[38;5;124m'\u001b[39m, t1[\u001b[38;5;241m0\u001b[39m]) \u001b[38;5;66;03m#we can call the first element\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m \u001b[43mt1\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m10\u001b[39m \u001b[38;5;66;03m# the [0] index refers to the first element\u001b[39;00m\n", + "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" + ] + } + ], + "source": [ + "#try to change a tuple element (this will raise an error)\n", + "print('this is the first element of t1:', t1[0]) #we can call the first element\n", + "t1[0] = 10 # the [0] index refers to the first element" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sets\n", + "Sets are defined with curly brackets `{}`. They are **unordered and don't have an index**. See description of indexing further down. Sets also have **unique items**.\n", + "\n", + "### Set syntax\n", + " \n", + " s = {item_1, item_2, ..., item_n} \n", + "\n", + "The primary idea about sets is the ability to perform set operations. These are known from mathematics and can determine the *union*, *intersection*, *difference* etc. of two given sets.\n", + "\n", + "A list, string or tuple can be converted to a set by `set(sequence_to_convert)`. Since sets only have unique items, the set resulting from the operation has same values as the input sequence, but with duplicates removed. This can be a way to create a list with only unique elements. \n", + "\n", + "For example:\n", + "~~~python\n", + "# Convert list to set and back to list again with now only unique elements\n", + "list_uniques = list(set(list_with_duplicates)) \n", + "~~~\n", + "\n", + "### Mutability\n", + "Sets are ***mutable***. They can be changed after creation.\n", + "\n", + "### Set examples" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Set s1: {32, 1, 3, 6, 86, 8}. It has 6 elements.\n", + "Set s2: {21, 6, 7, 8, 26}. It has 5 elements.\n", + "Union of s1 and s2: {32, 1, 3, 6, 7, 8, 21, 86, 26}, which has 9 elements.\n" + ] + } + ], + "source": [ + "s1 = {32, 3, 1, 86, 6, 8} # Set with integers\n", + "s2 = {8, 6, 21, 7, 26} # Another set with integers\n", + "\n", + "print(f\"Set s1: {s1}. It has {len(s1)} elements.\")\n", + "print(f\"Set s2: {s2}. It has {len(s2)} elements.\") \n", + "\n", + "# Find the union of the two sets\n", + "print(f\"Union of s1 and s2: {s1.union(s2)}, which has {len(s1.union(s2))} elements.\") # we note that duplicates are removed " + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The intersection of s1 and s2: {8, 6}, which has 2 elements.\n" + ] + } + ], + "source": [ + "# Find the intersection of the two sets\n", + "print(f\"The intersection of s1 and s2: {s1.intersection(s2)}, which has {len(s1.intersection(s2))} elements.\") #both 6 and 8 are in both sets" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "set expected at most 1 argument, got 6", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[11], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m s1 \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mset\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m32\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m86\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m6\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m8\u001b[39;49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# Differnt than the dict() function, we cannot use set() to make a set from integer values directly\u001b[39;00m\n\u001b[1;32m 2\u001b[0m s1\n", + "\u001b[0;31mTypeError\u001b[0m: set expected at most 1 argument, got 6" + ] + } + ], + "source": [ + "s1 = set(32, 3, 1, 86, 6, 8) # Differnt than the dict() function, we cannot use set() to make a set from integer values directly\n", + "s1" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "List with duplicates: [1, 2, 3, 4, 5, 2, 2, 3, 1]. It has 9 elements.\n", + "Set s3 created from list_with_duplicates: {1, 2, 3, 4, 5}. It has 5 elements.\n" + ] + } + ], + "source": [ + "list_with_duplicates = [1, 2, 3, 4, 5, 2, 2, 3, 1] #create a list with duplicates\n", + "print(f\"List with duplicates: {list_with_duplicates}. It has {len(list_with_duplicates)} elements.\")\n", + "\n", + "# Create a set of the list (which removed duplicates)\n", + "s3 = set(list_with_duplicates) \n", + "print(f\"Set s3 created from list_with_duplicates: {s3}. It has {len(s3)} elements.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If a `list` is wanted again:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(s3) #convert the set back to a list" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "List with duplicates: [1, 5, 4, 2, 3, 4, 5, 2, 2, 3, 1]. It has 11 elements.\n", + "List without duplicates: [1, 2, 3, 4, 5]. It has 5 elements.\n" + ] + } + ], + "source": [ + "# With Python, we can use set() to remove duplicates from a list and return a list without duplicates in one line:list_with_duplicates = [1, 2, 3, 4, 5, 2, 2, 3, 1] #create a list with duplicates\n", + "list_with_duplicates = [1, 5,4,2, 3, 4, 5, 2, 2, 3, 1] #create a list with duplicates\n", + "print(f\"List with duplicates: {list_with_duplicates}. It has {len(list_with_duplicates)} elements.\")\n", + "list_without_duplicates = list(set(list_with_duplicates)) #convert to set to remove duplicates, then back to list\n", + "print(f\"List without duplicates: {list_without_duplicates}. It has {len(list_without_duplicates)} elements.\") #the list also sorts the elements in ascending order" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The `in` operator\n", + "The `in` operator can be used to check whether a certain item is contained in a sequence. The result of the evaluation is a `boolean` (`True` or `False`): " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "2 in [1, 2, 3] # see if 2 is in the list" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "l = [1, 2, 3, 4, 5] # Create a list\n", + "\n", + "#see if 3 is in the list\n", + "3 in l #similar to above, l is the same as the list [1, 2, 3, 4, 5]" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "'ma' in 'Denmark' #when might this be useful?" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "'er' in 'Denmark' " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Extracting values from dictionaries\n", + "Dictionaries differ from data structures like strings, lists and tuples since **they do not have an index**. Instead, a value is extracted by using the corresponding key:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Value for key 'My': 154\n" + ] + } + ], + "source": [ + "d = {'N': 83, 'My': 154, 'Mz': 317} # Create a dictionary\n", + "print(\"Value for key 'My':\", d['My'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "See demonstation below, where the key `'a'` is defined twice. The second defintion overwrites the first one." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'a': 4, 'b': 2, 'c': 3}" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "{'a': 1, 'b': 2, 'c':3, 'a': 4} # Dictionary with duplicate keys, the last value for 'a' will be used" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Copying mutable objects\n", + "When copying objects that are mutable like, lists or dictionaries, there are some things to be aware of. This is demonstrated by a list example below." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3]" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = [1, 2, 3] \n", + "y = x # <-- This does not make y a copy of x \n", + "y # It makes y a pointer to the same underlying object (or id) as x has" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x after append: [1, 2, 3, 4]\n", + "y after x append: [1, 2, 3, 4]\n", + "y after pop: [1, 2, 3]\n", + "x after y pop: [1, 2, 3]\n" + ] + } + ], + "source": [ + "#if we change x, y will also change\n", + "x.append(4)\n", + "print(\"x after append:\", x)\n", + "print(\"y after x append:\", y) # y also changed because it points to the same object as x\n", + "\n", + "#if we change y, x will also change\n", + "y.pop()\n", + "print(\"y after pop:\", y)\n", + "print(\"x after y pop:\", x) # x also changed because it points to the" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "135995811464896" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "id(x) # Behind the scenes, the variable x gets assigned a unique object id" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "135995811464896" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "id(y) # y is seen to have the same underlying object id" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This means that when we mutate (or modify) `y`, the original list `x` gets changed as well, which is often not desired. This is because it's a pointer to the same object as y. This is often not the intention!\n", + "\n", + "> **When copying** a mutable object `K` use `K.copy()` or `K[:]`.\n", + "\n", + "An example is shown below by using the `list.copy()`method:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3]" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Redefining x since it was mutated above\n", + "x_new = [1, 2, 3] \n", + "\n", + "# Copy to new list\n", + "y_new = x_new.copy()\n", + "\n", + "# Show list\n", + "y_new" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 327]" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Append a value to y_new \n", + "y_new.append(327)\n", + "\n", + "# Show list\n", + "y_new" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3]" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# x has not changed\n", + "x_new" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x_new has object id: 135995815497024 \n", + "y_new has object id: 135995811502464\n" + ] + } + ], + "source": [ + "# Print object id's as f-string \n", + "print(f'x_new has object id: {id(x_new)} \\ny_new has object id: {id(y_new)}') # the \\n creates a new line, the id's are different" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 1\n", + "Make the below list and remove the duplicates from the following list:\n", + "\n", + "~~~python\n", + "L2 = ['Hi', 'Hello', 'Hi!', 'Hey', 'Hi', 'hey', 'Hey']\n", + "~~~" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 2\n", + "Given the dictionary\n", + "\n", + "~~~python\n", + "d = {2: 122, 3: 535, 't': 'T', 'rum': 'cola'}\n", + "~~~\n", + "Show that you can extract the values by calling out the keys for all key/value pairs. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 3\n", + "Find the intersection of the two lists (elements that occur in both lists)\n", + "~~~python\n", + "s1 = ['HE170B', 'HE210B', 'HE190A', 'HE200A', 'HE210A', 'HE210A']\n", + "\n", + "s2 = ['HE200A', 'HE210A', 'HE240A', 'HE200A', 'HE210B', 'HE340A']\n", + "~~~" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next [Module](./Module4-SlicingAndIndexing.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "p310env", + "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.10.19" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": { + "height": "168px", + "width": "267px" + }, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "165px" + }, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Exercises/Intro2Python/Module4-SlicingAndIndexing.ipynb b/Exercises/Intro2Python/Module4-SlicingAndIndexing.ipynb new file mode 100644 index 0000000..d90a100 --- /dev/null +++ b/Exercises/Intro2Python/Module4-SlicingAndIndexing.ipynb @@ -0,0 +1,415 @@ +{ + "cells": [ + { + "attachments": { + "image.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAh4AAACVCAYAAAAXK/N4AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAACmRSURBVHhe7Z0JmBXVlcdvs0izCbaiBBQIIBBUIEQZhgEkZKIGF4hbEIkSshlNjEPmU8IkImRCiDM6aAbFBUISNcQF0aBBYxiIhiAisghhUWSXfVGERra5v/PqPopHA728Lvo1/9/31Vf1qurVcuvee/7nnFvv5R30OCGEEEKIBKgSzYUQQgghyh0JDyGEEEIkhoSHEEIIIRJDwkMIIYQQiSHhIYQQQojEkPAQQgghRGJIeAghhBAiMSQ8hBBCCJEYEh5CCCGESAwJDyGEEEIkhoSHEEIIIRJDwkMIIYQQiSHhIYQQQojEkPAQQgghRGJIeAghhBAiMSQ8hBBCCJEYeQc90XLpWPy4cx8tjz4IIYQQolLS+EupqYyUXXjMGuLctnnRByGEEEJUSlr2d67FDdGH0qNUixBCCCESI6sRj4PdRjtXs4EtCyGEECLH2brQ5c0ellpWxEMIIYQQuYaEhxBCCCESQ8JDCCGEEIkh4SGEEEKIxJDwEEIIIURiSHgIIYQQIjEkPIQQQgiRGBIeQgghhEgMCQ8hhBBCJIaEhxBCCCESQ8JDCCGEEIkh4SGEEEKIxJDwEEIIIURiSHgIIYQQIjEkPIQQQgiRGBIeQgghhEgMCQ8hhBBCJEbeQU+0XDpmDXFu2zxbPNhttHM1G9iyENlkz56q0ZKvZxlVNi8vL1oqmrJW8aTgPnLlWkvL8Z6VEKL8oH/Jzz8QfSomWxe6vNnDUsst+zvX4obUchlQxEPkHBivYMBkyIQQIreQ8BA5RzwqUNkjBEIIUdmQ8BA5jSIeQgiRW0h45DAzZ85y06a97hYvXhqtOZzjbS+K9es32HeYKjJEOiQ6hBAi95DwyGGGD/+F69nzK65fvwHRmkNs377DdenS07ZPmvTHaO3xmTLlz/YdporItm3b3PPPP+/uvfde98tf/tJNnz7dFRYWRltT7HrvPbdm3Di3c9GiaE3uc8Df49Zp09z2v/3NHdi9O1p7JPs/+cRteuklt/7ZZ92BXbuitdlj7+bNbuOLL7rNr7zi9u3YEa1Nnr3bt9s1fPTOO9Ga7LDj7bet7lCHyoPtb77p1owf7/asXx+tqVxwbxsmTYo+ZReeybqnnnLb//53d2DfvmjtycOWqVPd2t/9zhWuXRutOcSTTz5p/SH94jPPPBOtrbhIeOQw119/jc3nzp3vVqxYacuBuNjo2/faaCn32bJli3vFG5ylS5e6WrVquerVqx8R+dj1wQfWQD9ZsiRak4JOa7lvnGFa99vfusI1a6KtFZv9XkRs/vOfTXzsP4bwoCw2/elPbsPEicfcr7Ts9cJv4x//6Lb4a9n/8cfR2hR7t251Kx98MF2+K0eNcrv9sygP7DomT3Y7Zs+O1mSHj+fPd6vGjHF7PvwwWpNddrz1lvvQ18M9GzZEa/y9eAG3+vHH3Zpf/9rtXr06tc7fHwIIIZRL45g+9AaQ+lce7F61yq31bfajOXN8g9gfrU2B4KY+vD9yZHo68Omn0dbKwbY33nBrxo4tUvDn5+dbfzhz5kwTIRUdCY8cpk+fK63CAZGKOK+++prNe/To5po1a2rLcUilZEYKsk2mGMoWderUcZdccon7wQ9+4Lp06eJq1KgRbUmRV7Wqq1q7tsvzoiQOhhtDWLdtW1erWTMzMit/9atyM44ngiq+86lyyimuCvWiHFJRedWq2fEpW5YDRGQQHYXr1ln5MtVu08ZV9c8ql6ji61JelSrldt32bPwzoo4GLErlxfSmKVPcx/NSP02wb+dOE3gmnnNIeFSl/tWsGX3KLvZsfLnZ8WN1+9NNm9w6b2xp36c0aJCuf+UVeTlRVPX3Td0sqnyvueYa6w87d+4cranYSHjkMPXr1zNhAS+++JLNAUERhEiIigBjPUi/VKlSx1IptWqd4Zo3P89NmPBstEfRsC/fGTjwlmhNCr7L+mHDRkRrUucI+7O9oKCxGzJk6BEih/QQ+40ceV+05tjg9WV6fvF18WU69+qnnZYyvjFotDWbN3cNrrzSneUb6llf/arb4w0lIUw6/8oCoqt6/fp2v9mGssW4YJgxBAE8+W1/+5tr4AUh5ct0xmWXmSHIJarVretvsorLP/vsaE12wWhULyg4QhRjVKqdeqr7ZOnSw6IhuUY13+6q1asXfcouJmp8udG2g/BA8G57/XVLvzS49FLX6IYb3JlXXWXTqR072j6VhWq0aX//Nc46K1qTu0h45DhBWMQjGDNnvmVjPICoSODqq/vagNOGDc9yAwb09+q4k0UlEBQlGYB6NBiY2qXLF9MDUxFGXAfiIlO0cI3st3TpsmhNdkB81O3QwbX62c9c/X/6p7QYyQRvvd5FF7m655/vdvnOfr/3MGHrX/7i5l53nU3vfvvbbuv//Z+th3VPPOFW/M//uOUjR9r2+Tfe6NY//bRt27VsmXvvnnvc6jFj3Dy//v2f/9yteewxN79/f7fx+edtH9j08stu/k03pY7/rW+5Lf58AdJDa8eOtfPwvXn9+rnVjzwSbT2Sf/zwh27BN75hYx3iNLn1VvfZH/0oZUSzzClnnuma3XGHO8dfe9zAIHIIAe9cvDhaczgLv/tdt+W1VBQuQGqGsiQ0f2DPHguNv3PttemJ8QJxCLXP9WXCNu79oyg6ECCCNd+XB9vn+fKjPAObXn3VfXD//TbN9cbpna99zS2/995o6yFO697dXTBunImD8qDB5Ze7c4cOdTWbZkQhffnVaNjQHdy711KFmVC2pIBC2cy/+eb0/VPHP/T1kLJkDEnYh/QNY2E+eOABt8JPmXz4zDNWvz7dssU+f3DffenvLhk8OP0s1/r6uPC22+xYAcZPLfmP/3BbYu0Dzh02zDW55fC2ni2IoLXx11jQs2c62kZKausbb7j8Jk1cwRe/aOIkULtly2jJC+N33nHvfu976ftb/9xzVueAerXspz916315LBkyxLYv8vWL6N3B/fvdMn9PpL1YT7smSkobX/3oo25flG5k3EU4NtPGlw45gjwH6t17vk9iG99lnBRsnzXLvZvRNkjzLf+v/7LvhePDWVdf7dr+7/8edo+5ioRHjhPSLYiOYPDjaRZEBiAsgrh46qnxbty4MW7GjKkmDvgu40TKyr333m9Cg+tZvnyh27p1rXvooVG2jagKoifQufNFdn2tWp0brSk7YaxHNe+N12zWzAzvsd58ySPs7T3NT70BxOjtmDnTjFFj36l/7sEH3ek9erjVXjxs9+uBAYF0TnRYbMer2vjCC+7juXNtwCdh8i3TprkzfMdImHzXypWubvv21jHu8R0Tx0HktLz7btfmv//b1W3XzsaZsA4+9Z7uat/B0Wm19Map+V132XHC+QOMS0GY+Jtzrb2xOa1bKuoVqPGZz7gajRt7F/FQOD9bmMflj30KXlcsolL38593jb/+dbfWi4W3r7giLcgCGEfEWRyEx84lS1IhZP8s5vbt6+p16mRle47vjDdPmWIGFQpXr3aLBw1yp/3zP9v2Ft7o1fGGKPDxu++aUbDt3sgivjZ447LuD3+w7RgoRB/GtNV//qeVLaH5TNFW3YspjhtPhWSTU7ygQXRUzYjGQa0WLUzw7PDiIT5+hvpGKgGvnvvm/k/15b18xAi3a/ly24e686G/V4xh0x/8wH3GCzTGBOxescJV9WVL+WRCihHRQRtZ58UF57ay9caX+sw4IcRGvQsvdLt9Xd42fbp9b99HH5lg3u/ntc89vP1yb/m+/pUH1BMrI/+MQrve7/survGU00+37UVBHVv18MOuXseOdn+f8cJz7W9+Y4KXekn5bvX3hqGv87nP2T6MqeL+iahQdggFHBnaMuNwavn7RjSQEmMsFaKP7zHRLyBsEDuAkKDfQCyx/XTfP6z3x/544UJX94ILLHq4KSY8EJ47/bZazZtb9DLAPWaWd64i4ZHjIBz69LnClkO6JQwsjadZ2rRp5Q4c2Ol27dpsn0nFEIUIkZHMVEhpCOIFQbFixSoTQowvCeNQ4ukgxM/UqX9ygwf/KFpTekJUo6joRlHrDsNvP3jggM03+8Z/6he+YB4V4VwiInTGiIZALe9F0flj3PO9uMnznV3wBDnO2QMGWHqBThABggg66EUNnhPHO/vb33b5keE+rWtXM77B4wS83lbDh1vHRrif8wTjAh8++6xb4M9R4EVR61/8wo5TETwgruEcb+wv9J15g698xX3ghdWc3r0tBQPc856NG63Txptc4zt+BlVW950p4flNkye7g94ANPFeKWV/Wpcudo8MJKTj3uC3U9ZnDxzo8hs1ssjLYame2bNddb+OiALPjE4bEfOJFxqhDiCYmt95p6XbQtkWVqC3SzBMGCKMXvzNBYwfAqnBZZeZkOX+G3rPGbFGRM48d3+PlAnlhxAlkkdagjdBKA+ECYLhfS9W8Oo/9c/i082b7XiUf8PrrrOJss8/5xyX7wVE+E7tVq1M6GyeOtWuh/qOgENsmsA90fB8IxG8euxYN+uSS9wM/+wXePFK2XzsBUCe3+f0L33J7u+MSy91ddq2dR8vWJD6rodxN0QUSNVQvojPXV608fYM9YxIWH3fXkl3UDfpB+zNGt/mSem28uXKsZksmuW37Y8NAq3jn8dn//3f7dg1P/tZE/CULf0EDs62v/7VHfTfoWy3z5hhIoNnWB7p0oqAhEcl4KqrUsIDMUHqhMgGxj6eZgEESdu2X7CxFb16fdWNH/9EtCU7IDYg/kou5wmihlRMeRCPaoRljM3xRAdhbTzh6qeeap0LuXW84DneY8FrX+gNKYaLcCfGwPAdQQjzciY7X+w86W2+Y7GoQAwGCpJmme2NI8f/x7/9m8u8wlq+UwopDIzy+Y895hp57zXAGApEyTbv/eJtVSSIEnDNTW67zX3eCyTExtpf/9qEA14wc8bSYNB2ezHFeAbKnY6bsi/005w+faxs3sZrjLzEAzwnL9BO8Z165tiIANsRKaRY+D7hbEtj+WfDNuBZYYzT9SVWbyoKGHlg7JEJYg/zvd5IISCCIUKg4g2baI32Y1wP0Qn24TjUHQQKImyv34/6YukDb+A2v/qq1V8EI6IYYfPWl79sZUca6sMJE9Lth+M19M/lo7fftpSPCRI/L/CGON72TgSMOarmy4FnTNTynG9+03Xy98b4Ld58oe4gshCmC7xo5f6CICZaEiA6WrNJk3T7JVX5OS+ecRyAuk05cK6qpDBj980r5ojp2V4YcvylP/mJ2/X++9HWFHyXupf6EH03Kt8zr7zS2v26J56w/ghxTtoIIVlZkfCoBBDxQGggOvhtD4inWYDIRr9+37B9eL124sTfu0WL5hy2T1nJz095oIwfIZqROd155yDbnm3oIOkAS9IJIjoYDEkHUd97MHgydDJ4ix1feMFd9Npr6anxgAFZiSoQBscwd5w40V3kO8dzhw+PthQfBiA2/f73bUzKivvvd/uiaEtx+cQbfl5Fft/f915fBuUFUR8boImh9M+nznnnWdj/I28ATvuXf7HwMsaAztiMh+/MTznjDNfBG7xOXjCEibQIBqGG74QxFHj/wZiEcTnA8yFM3m78eHtm4fvn3nOPeY/ZYrkXTHO8wNnpz308YVsaEBenduhgIi28NonRozxJd4RXRD9ZtszuH+/6eGkhIm1ERxAOIZW0w9/DQd9eKDfSWIxBIAVBmX3eCz7SBXGIBFK+REwQ50QAgkgqLh97Ab9gwQIrw2xBvSF6gai33/eIyieAwaeuEbE5//HH0/WCqfXPf27bywrjPyjD9r//vbvICzhSqSUdnIz4IP2Co4OQrJ8jb6eUFgmPSkAqupGKeoQoRjzNAkQ7iDywL+M7iIbwuSRRiPi+RFUyv9umTWubI24QPmFibMf06a978XPISJbmV1WPRqbgOJpBwHMkbYLgIN9PjpcQKKFTPO8GvXq5Qt+58zsL7MOEZxQ85rKC8eRKd8yaZb/HwTiItBdUAjDizbyHRR6YvHQ8FXM8lnmD9X0vXAZ4MbXad5bZYs+aNekyY+IHzBiLUuCFHJ44Y26IapDXLrj4YiuLT/7xDws1Y/wQfHTWGEDy6GEKv7OCMcbT3uBFIW8hMfYD7z1gHbV/vh/6zp+xDXyXsTHZ/p2WkSNHuov99f/FG67ygueL8MD7Berm6d4D3jZjhtVZ7o0xBDag0l8LouJ4IL4YL0RdRzAQUSENQdSEZ0DaCRHLsRkwWtQPszXq399EB8+NNGJJ+Yf/Xu/evd13vvOdrKR2ASFO6qSGrzsbnn8+XT7UDaJjoW5RhtRJtoWJMs6GeDTx5/sg2iHpWtp2SfuMhtdfb9FABq7yTBHhlZmq93ii5dKx1jfAwsgANb3cS/ZDg2FEcuzdu88991zqvXXExWOPjbZ5AJHw5JN/cPvIPe7f7z2PRW7QoMHpMR69e1/hOnRoZ+M0Xnhhsq0bOnSIzd98c7abPXuOe++95W7evAVeRLzhfvzju9PfDQKDNsw1kHJZuXKV27Ztu0VgRo9+xB/jLTsev8EB3btf4h54YLR54Jz7eOzblxIX/HLpbO8pN27c2J3nO2ig0afDwpEIYR6mAIYPL5EQPwYJT7DRjTdaFALoQOigd3jPkH3s1UbfgdU85xzzOOmY8Rjree8P6LgJW9f2niDpEdIxp7ZvnxoQ5q+nfqdOdl3mlflrxXNnnMNO3wEXrlplg9XI+ZLL5RrwcMkR48HRUR6GN6oMOMRAMMCMQXZ0uuTwq1SrZiP+i8Mp3khRfq/5DrJfv37uM/542YA0B2IulBu/rcDrjbxSywBerhVRh9FjrAIhbcqLsqzdurWlURAXDNgLx2Ci3HkupG0oVxvz4Z8Jz66e92IRK4SpST1QvgwE5I0LvkuEgPPymy2kGYis2PMheuXbAOXN9XD84rLJ39csf41neuHUo0ePw+pXaaEOke+v48uBe6COMWART506hGhjG/WNSAX3xjYGQdeMPGsbLxDtXxSMp+H+iWRQJhyLcxEJ4PVM6h1RA/vdkL177Tg1GOvg662Vl4dxHwxyZeyMpTJKSG3//F566SW3yD+fr3/96+5Ufx3ZgCgRbQahxptNlA+CHjFK26JN84wZ/B3qBlO+rzPUH6KfGH2cEOpRJkTXaHO2r39WRH4Qa1affJ1lnAwRD+oeUT3qG+NfrF77+mvpXH8N1FcIvzzMNaejcb6fsPFIn35qg7QR66Xhb17041D07ds3WnMk1aqVUGzt3uTy1qUGFruCdn66ILVcBvJ8x1g2yTfLG6dt0Wtd3Ub73ju33tuvLOBBFBScbfPLLvuye/nlQ69wAusbNWqRFgvA67REIYg6EAEh/ULEJLz6ymBUQLR07NjlsAgH50CksA5BEUTKoEF3uVGjfD2IwQBYBpPynQC/8UFkhLQMEZjjUViYCs6RInj44YddJ9/5Xe+9hAAGIBvey4kkiXvY6j2xn/zkJ5Yu+N3vfufOTXiUfDYM9Ylk/PjxDl+Nn6a+7rrrcv5+SgKRJt4cavvggyZISsrmzZtNcNAX8bcH9UtpXCsjDNZdNnSoiXUGUJcW6uWMGTPcpKP8eBr9S35+akxQsdm60OXNHpZabtnfuRY3pJbLgIRHJQIhgLBo1qxJkb9WisB49NGxtk/37l1trAfRCcQD4zMQIiyH9AdRjADfIUIBrVu3stQO5yss3HPE+UijvPJK6vWwet57Q1wgPuKwD99ljAlv3ByPuPAg3P2R9/A+5z2Pbt26ua5du1p0h6ocjHfcIJS1iidFeQuPhQsXmuFct26du8p7vlcyqC3yZpMiVw01kY4pU6aYWGvXrp376U9/anX7ZMDSK94wbpk+3d76aHjN4Wnc4vD666+bMWR8x/e+9z375WGReg2ct1iIshJtOYe33qIoVkkYO3asW7VqlXvzzTetL5TwECILBOGB4HjrrbfcypWpn2PHCLRv3/6w/2yhSkt4HMkHH3xg3lDTpk1dx44dExcdkKvCg8gg/4NBxOhS75WeHkLkJwGMcyJtFVI1pWHevHlu/vz53mlp7S688EJXJQuDOisDjAvhtV5SX7xeT+q1NEyePNlt2LDB2hdpaOpoUdC/SHgIUUyC8CiKYLCLmkNZq3hShOuuzIRnIoRIHvqXiiA8JDtFpSAYtMy5EEKIioWEh8h5UPFhEkIIUbGR8BBCCCFEYmiMhxBCCCGKRmM8hBBCCJHLSHgIIYQQIjEkPIQQQgiRGBIeQgghhEgMCQ8hhBBCJIaEhxBCCCESQ8JDCCGEEIkh4SGEEEKIxJDwyHHGj3/CValSx6Zp016P1paN+DHF0Vm/foMbMmSo69Klp2vbtqO79dY7svYMxOGMGfO469nzK1bmongsXrzUXX31DVY3mVhW/SwdU6b82epfo0YtrL0PGnSX6mIZkPAQohQUFhZaRz5y5H1u5sxZ1sljHHv1+qqbO3d+tJfIBpTnoEGDzWhS7uL4rFix0nXs2MVNmvRHq5tMLGM8cSxE8Rk1arS1a+ofYoP2zjoEyPbtO6K9REmQ8BCiFIwZM9Y6oPz8fHf//b90Tz013rVp08oMI96QKBt06JQjnTsGVIKjZBCJo8yokzNmTHVz5sxwHTq0S28TxYN6GMprxIhh7sCBnW7ixN/bZ8QdYk6UHAmPSgheOJ4NHTcqnc6btAkdOCHDOMFQsq2goLF58UdT8cFjqlXrjHRqIb7vsGEjbDtTCEPirYZ1RAQCeAzsn6sN98UXJ9u8b99r3R133GZzBAjMnPmWDGUZ2b59u9URxJ0oOUQ44Pbbb3WdO3cy0cEy0DYxmuL4UA9DW6adQ58+V6ZF3MqVq2wuSoaERyVk6dJlJjgmTZpsIcLQeSMCQsgwgNCgg2cbIgIhMHz4iGjrIQjPhhwxDTGkFhAgQWTcfPONZnTZJ3j9AwfeYp/Zv2/f62wdPPjgQyY8XnzxpWhNbhHKsF27C2wOzZo1tTnlo3RL2aAs8S6Zpk79U7RWFJebbrrRDR06xERH4GgOhTg68XpIdBMQbUG4tW9/qP2L4iPhUYmhcRAe3LVrs4VaQ8N5+unnbI7ICBGQAQP6u3Xr3nfjxo3xhnOPrQtgSEO4EbW/fPlCC9/SKBEdQWTw+e67f2zLEyY8a8IiGGCOW79+PVuuTMTvKT+/RrREmR1ehkIkCd45wiN45oiORx8da8ukX4JIFsWHvozocfPm51l50mfSH4qSI+FRiaGDoQNCcNABde58ka0PocN4tIE0QcOGZ1ljuuyyL0drUxDFCFENhAWdFp4UEQ4gshLgfKGzQ3hAUcdEvOBFIEiEEOUHRpJUJ1FHhPLEiROiLaIkUI7x1B99YuhLRcmQ8KjEICSORRATCIW45969e9doKUU8H8xYkPCqbRAWNL6wDyInLia4hjD2QQiRLBhK2izeOg4DkU8cElFyevTo5hYtmuMeemiU9XNEi4cP/0W0VZQECY+TmJKmPmhshG+LmurXrx/tlXrnPYC4Wbx4SfSp8hDSVkG8QTy9Ek+7CHEiYFxWz569zCkgJYDoUIqlZNC+Gc8VIh2Itltu+ZafvmmfMwfri+Ih4XES07p1yvPBG4pHNcIbG4GQOiGy0bv3FWmx8d3vftNdfHE3m4KIIZwbvIBgnBlgWtlCkng/MH/+AptDGM/CfYcyE+JEgLEM7W7w4B/ZK6AldTREqj8jTcXYjjisF6VHwuMkBuEQxAFvrDAgNLyCGweVH9I2bGc/lD5vyNAoeUMlEDo79g8DWuNiJMAALdI17J+LXH/9NTanLBh4S9opDMBlLE0oVyFOBPE2SXsOr7SHKR6pE0cHByK05X79BlhfFvo/iL81JIqPhMdJDOIgvIWCt07D4tXazHAsDY9xG8zpxNgv/EInDTOM6Qi/4gm8TZMKS6ZCkvFtlYH4iHbuDeFB1AivUgNmxYlm2rS/RkupcR602/hU2SKQ5QXtmb4MEBz8fAD9H9C/hW2iZFS9xxMtl461f3GuMFLPTS93rnrt1LJIDAQEoX8mxlocPHjQN4rWlgKJh/z9avt88cVdbTt07drFNW3axOXl5ZngGDLkTvfDH9522DGhZcsW7ppr+rj9+/e7OnVq2763336be/jhB/zn1H+6vPHG3+14l176r+77309FMriGatWq2XGYn39+W1vPteAtxK8l1yDt1LhxI1e3bh139tmN3cCBN7tf/eo+5dHLAep1qj52VzTpOCAq9u3bn26/RU8qx+KS6qe6uR07PrJ+MfR9jz02Ot33VWp2b3J566anlgu8PSko+2+X5Hkj5U1AGZg1xLlt82zxYLfRztVsYMtCCCGEyHG2LnR5s6PITsv+zrW4IbVcBpRqEUIIIURiSHgIIYQQIjEkPIQQQgiRGBIeQgghhEgMCQ8hhBBCJIaEhxBCCCESQ8JDCCGEEIkh4SGEEEKIxJDwEEIIIURiSHgIIYQQIjEkPIQQQgiRGBIeQgghhEgMCQ8hhBBCJEaFEx7bt+9w06a9btP69dHf7cdYvHipbZs5c1a0pmIxd+58uz6uMwkoo1BelF02iB9TCCGEyCYVTnhguHv2/IpNV1995N/v3nvv/batX79vRGtODHGBFDf4gwbdZdfHdSbBlCl/TpcXZZcN4scUxaNjxy6uSpU6NkmwZQcE8MCBt7hatc5Ily2fsyWwKzs4Z23bdkyXXUFBYzds2AhXWFgY7SFKC7aJMl2xYmW0RpSECp1qoeGMH/9E9KliERdI2TL4IjehjqoOZBeMI20rtP82bVrZnM9XX93XlsXRQbT17NkrHXlt2PAsE2wIj1tvvcPWidIxatRoN2nSH6NPojRU+DEeQ4YMLZFCL06Kg0ZZnGOyT0m916lT/+QOHNjpxo0bE60pOVxftr264hjG4qp3qfxD8Jyoo/Xr14vWiGwwadJka8sYzK1b17hFi+a4hx4aZdtok6qDx4aIK/1Xhw7t3PLlC20aMKC/bUO80ceI4hMcTaJvRLVF2ajQwiM/P98aCB37saCBoeIJfYXQIqGwzMZFZ0VIvFGjFukKhAfA/vG0ApEW9mMf1rO9efPz0iKEVES88rEcPLOwPyFh6NXrq0ccH9jOeq43MGHCs3ZtTIRFOSfnKinh2JwTdc59hPvhfuNQRuEaOR/Xs3Llqmjr4YwceV/6uti/S5eeh421CedlCkIHzyCsi5+7X78Bdn0cM5cZPnyEleGIEcOiNSIbLFmSciCIdNAPwGWXfdnmoHTLsQkOGGXWrFlTK8PvfGegrYOkxqBVNjp3vigdfROlp0ILj7vv/rE1mDFjxh6zoTDeY8yYx20ZDwkweBjb0EEhTjCUcc8fo/zAA6OjTynYD9HCfhwLLwGvAdGCgS6pp3D99dfYPHMsSAjVfe1r19qczxhjjs89M4Vzljasxz0gikKZcG8YfwRO+EyZxMUN5ZwpTgDxx8Q9BO8e0UE4N5Qpxjeca/jwX9jxmQNleNddg2wZZs58y8pk6dJl0Zrcg/umDvXte+1hRlGUnaFDh1jkkAhi4NFHx9mcOkZ9EkeHtkjZxcVGvO/Kz68RLYniQH2jPJnuvPNQPyZKR4UWHnQwGCsM2NHCW3T+wTATil237n0LK2K4aWh4pIB44TNGc+LE31undv/9vzzCc+J4oYFSyUiZhM6P68DYYmT4boDlEMbMBKPEtUAw8BwjnPfmm2+0eTDQffpcaaFlJpZh0KDBNi8pnOPll5+38ti1a3NaFPz1r2/YHAESQtbcA2UyZ86M9PUGKA8MLNxyy7f8ta21qXPnTlYmISLF8UO58EyCgON4lGP8uHgOPXp0c61anRutyT2IslGf4nVBZB+cCiJmITpGnRbHBkNJ+yLaAfQFoY/BY5dwEyeSCj/GA+GBQcNoF+X5B2OOUWvTpnWU/12VblghPfLqq6/ZHGMeDPodd9x2RNgMY4oBxlBjcDlnSJtAplA5HlxXnz5X2HK4hldeSc05Fx0D5wlRg+7du1o0gKl9+wtsHeKgNKFRjh888VT5pO4VsQBBgLDtllu+acuUW7jeAOcO3+H6KFOuNxyPZxC2x73/8Gx4hpkd3VNPjTdBN3jwj6I1FROMHSmh+ASk1hCQ8SiPKDmUY2b5hrYQKCzcEy2lePDBh6IlgUMWLzuippnQv4Rypa7S9uJOgDjE0dq7yC4VXnjQQMKgMjz/YOACGzdutDnr45UljD0IBjvMMZxxggiJQ2fIOAaOg9de2lRH4KqrUoY8GOIgPK666nKbhwgLxDuSeMojvk9xOV44NUQ7EAXxjiizjMJ+EMZmMIVxLRC/vngEAGEVT7HkGqSCEFrxCYjyUGYbNmy05xQ3hr/97ZPp/cSxYTxRZvlminscBByBMGCbelfWNllZQEzEyw6HJQ7rGLfFfrTzGTOmHuEEiEMcrb2L7FLhhQcgDggbYgAZ7R4nGEy875CDi08hLBuMcKZwiRtVQKAQ4cCQ4r2TliF9UxaIIBCS55hU5CCKQnombvRDaidzKo/OInjqmaIGYxonfn1FXRtT3OuPG+GinlkuQSqIuhefgDKjLiE6mEIqCjCM06erwyoOTZs2OaJ8aSu0Q9pKcBiog7SXEGUL0bqTHfqFeNmRwgxQJ3EQEHKUHaIjpF5E0RytvYvskhPCA4IXnSkc2rUL6YhV1imFyrJ9+3br/BcvXmLbg2F8+unnbB4IUYjAH/6QGnhJAyUkiegJQqG00GmGyMqtt/7Q5lxjuCauOxh3OolwD2znHpgy7zsbhMgG4iAuwF544XChEDr7QLg+xBzXRvmE68dYhIG+oZMjipMpbvhO3LBUVEgFZYosYPBjfMIrD9DJX3yxOqziQFllli/GlKgRRjO0F6Bt0M7hzDPPtPnJDv1ivOzos4C2FcbFUTczx1iJojlaexfZJWeEB51RvHMPBAONYeYNEIweYXDedImnKm6//Vab0yCJaIR0SmZY96yzUh0ahhiPgWMU9YM78TQGRjQzcpJJeLslGNrwOUB0BXj/nvNxH/xQEucnNROPKGQLOv1wXN5uodzCgNA4CI8QcaHsgofPvizH011hPAz7T536sh0f0ZE5OJjng2FJ6hdes02m8Aj1C2666Uarl6L0BFEc2isOAu0hCHC9RXRsEG4B2mp4pT1MlKsQJ4qcER7Aa0yZBpjPjAEhPIvBxGgzQIgOioF/vIUBRByCcUd0hHRKpoGIj/nAWGJYMaLhvC+++JLNGbgZjDEG+ze/OdTQi4LzcI2B+HkAz4XjcU2IDu4DkcJ5ymsUPx5Q8IQ4L+VG7pxzxmE7nhRlgMCiTEIUg/sIv2HBGJwgwLgfIh7h1TPeoAmv8QpxPBAWYeAx7RWnIhjL0FbE0cl0HoSoSOQd9ETLpWPWEOe2zbPFg91GO1ezgS2XFiIQodHgaWcKDYwxBo+IQ9xAsu6RR8ZGn1KvqRaVz8Swzpu3wJZ7977CfhsAQ09HFww81zBhwjM21qF161YmWLgm1sfPyzk5HvsRWkdchP247swURVHHyIRrCWMseKslU6BkwjWEKAqdcciPs57leAd9tGtj/5BiuvTSf7VyC8eMCzPEHK8l79iRihKFew4EwxC/P74TBrzFr4coEW8rFFVOuUj8PsNzEGWHOhtP/fG7N5WhvpQ3x4toqI6Wnnify5iaSp/C2rrQ5c2OfiCxZX/nWhz5H2olpcIJj/KCqATGDkMXvHyMBb8SijEmjRPGkQghhBDCUw7CI6dSLWWhU6cLzQsg3N+27RdsfEFBwdnpCIB+jU4IIYQof04a4UHKgldjSakQKkOEEG4k0sGvdSI+hBBCCFG+nDSpFiGEEEKUEKVahBBCCJHLSHgIIYQQIjEkPIQQQgiRGBIeQgghhEgMCQ8hhBBCJIaEhxBCCCESQ8JDCCGEEIkh4SGEEEKIxJDwEEIIIURiSHgIIYQQIjEkPIQQQgiRGBIeQgghhEgMCQ8hhBBCJEZ2/522SS/nqte2ZSGEEELkOLs3ubx101LLWfp32qwKDyGEEEJUUiqW8Hg3+iCEEEKISklLLzoqhPBY+xfnCjdGH4QQQghRKTntfOcKLog+lJ6yCw8hhBBCiGKit1qEEEIIkRgSHkIIIYRIDAkPIYQQQiSGhIcQQgghEkPCQwghhBCJIeEhhBBCiMSQ8BBCCCFEYkh4CCGEECIxJDyEEEIIkRgSHkIIIYRIDAkPIYQQQiSGhIcQQgghEkPCQwghhBCJIeEhhBBCiMSQ8BBCCCFEYkh4CCGEECIhnPt/oMQeSrt5v8oAAAAASUVORK5CYII=" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Indexing \n", + "When elements are put into a sequences (strings, lists, tuples etc.), the individual elements gets an index assigned to them. This enables each element to be extracted. \n", + " \n", + "> **Indexing in Python starts from `0`**, while the last element can be access via index `-1`.\n", + "\n", + "![image.png](attachment:image.png)\n", + "\n", + "### Use square brackets `[]` to access elements\n", + "To extract an element by indexing, use sqaure brackets `[]`. This is the general way and works for all sequences." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "First element: Denmark\n", + "Last element: Germany\n", + "Elements from index 1 to 2: ['Sweden', 'Norway']\n" + ] + } + ], + "source": [ + "country_list = ['Denmark', 'Sweden', 'Norway', 'Germany']\n", + "\n", + "# Extract first element\n", + "print(\"First element:\", country_list[0])\n", + "# Extract last element\n", + "print(\"Last element:\", country_list[-1])\n", + "# Extract elements from index 1 to 2 (not including 3)\n", + "print(\"Elements from index 1 to 2:\", country_list[1:3])" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Fourth element: 40\n", + "Fourth element (last element): 40\n" + ] + } + ], + "source": [ + "example_tuple = (10, 20, 30, 40)\n", + "\n", + "# Extract fourth element\n", + "print(\"Fourth element:\", example_tuple[3])\n", + "\n", + "#Extract the fourth element (last element) using negative indexing\n", + "print(\"Fourth element (last element):\", example_tuple[-1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `IndexError`\n", + "When trying to refer to an index that is **not** present in the data structure, an `IndexError` is raised:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "ename": "IndexError", + "evalue": "tuple index out of range", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[4], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mexample_tuple\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m10\u001b[39;49m\u001b[43m]\u001b[49m\n", + "\u001b[0;31mIndexError\u001b[0m: tuple index out of range" + ] + } + ], + "source": [ + "example_tuple[10]" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Length of example_tuple: 4\n" + ] + } + ], + "source": [ + "#if out of range, we can use len() to check the length first \n", + "print(\"Length of example_tuple:\", len(example_tuple))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Remember this error. You will get it a lot!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Extracting values from dictionaries\n", + "Dictionaries differ from data structures like strings, lists and tuples since **they do not have an index**. Instead, a value is extracted by using the corresponding key:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Value for key 'My': 154\n" + ] + } + ], + "source": [ + "d = {'N': 83, 'My': 154, 'Mz': 317} # Create a dictionary\n", + "print(\"Value for key 'My':\", d['My'])" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "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3NvtTXqYkYQoIOYsLmVDhpcNtoQQu0PvE7boxxtF7pj3jqVkJLNUs4OuM6t/bGR/gpBAEcWO7+akWr8h5YMtIcTucEfvNDut49ZgS4gckEARYveIFihTnnYvDl/VU1JSMt9Hw/7ckMhHJrfXFEWbZDSziaZ9v0hdlEARuSbJAkUxKKJEIUEghBBFAwkUUSLYuHGjff755/bhhx+6NGrUKPvjjz+cYPFJiOLEunXrbMyYMTZy5MjM9PvvvwdHhQg/cvGIYke0i2fy0Ej1/u233+yoo45yQqROnTpWunRpe/jhh+3QQw91x8GLlPT0dFu+fLmtXLnS1q9fbxUqVLBmzZq5V/CPjD8PocN55cuXtxYtWliZMmXc8dywu8KIa9PxzJ8/30qVKmVNmzZ1142F8xBl8+bNsy1btrj8V6pUKTiaeNasWWOzZs1yZRKPWrVq2f7772+rVq1yedq2LX4Q5l577WWNGzcOthLH2rVr7ccffwy2dqZ27dq27777ujKl7LifCxcutL///tsqVqxoDRs2tGrVquVZyO6qmV2xYoW7p9nRoEEDq1+/frAV+b7Vq1fb3LlzrXLlynbggQcGR7KgnG+55RZbunSpqws///yzvfLKK9ajR/z2WC4esdsoBkWI3SNWoNCpLF682AmUG2+80a655pq4HYY/7+mnn7ZPP/3Udbp0VPvtt58999xzroMFPvvrr7/a0KFDnVWGjmLDhg22zz772LvvvusEUG7JbYdHh87od/To0e4aEyZMcJ3WiBEjdujQEQiIAM5777337JtvvrFy5crZ+++/b23atAnOSjxfffWVXXzxxbZp06ZgTwTEEQKuV69ernPEctW/f3/X8UezdetW10lfddVV9sQTTwR7EwflddZZZwVbWWzevNn+/PNPu/TSS+3xxx93ZTVlyhR74IEHXIfO/5OammoHHHCA3XHHHXbIIYcEn9w9dtXMvvrqqzZgwIBgKwuuT/4GDRrkjlNOCxYscHVg7Nix9sUXX1jHjh3da04gHk888UQnyiVQRMJQDIoQeSc7AcD+2ESnSeP99ttv2+WXX+46eDqrd955xxo1auQ+R0dDR3rhhRe644id//znP+48RMCee+7pzks0WHMuuugiu//++61Lly7OUhMPRNW1115rt912m7Vq1co6dOgQHEku7du3d2KIcohO//d//+csSqec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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Slicing\n", + "Slicing is the operation of extracting multiple elements at once by calling out the index range. An example for slicing of a list is shown below: \n", + "\n", + "![image.png](attachment:image.png)\n", + "\n", + "> **When slicing**, the stop point of the slice is not included.\n", + "\n", + "Examples in this section are shown for lists, but the same concept works for strings and tuples. Set objects do not support indexing/slicing since they are unordered, and dictionaries cannot be sliced either as they have the key functionality instead.\n", + "\n", + "### Common slicing operations \n", + "Suppose a list `n` has been defined along with two integers `start` and `stop`:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The list n: [3, 25, 83, 31, 14, 47, 1, 23, 57]\n", + "start index: 2\n", + "stop index: 6\n", + "n[start:] [83, 31, 14, 47, 1, 23, 57]\n", + "n[start:stop] [83, 31, 14, 47]\n", + "n[:stop] [3, 25, 83, 31, 14, 47]\n", + "n[:] [3, 25, 83, 31, 14, 47, 1, 23, 57]\n" + ] + } + ], + "source": [ + "n = [3, 25, 83, 31, 14, 47, 1, 23, 57]\n", + "start = 2\n", + "stop = 6\n", + "\n", + "print(\"The list n:\", n)\n", + "print(\"start index:\", start)\n", + "print(\"stop index:\", stop)\n", + "\n", + "# The list `n` can then be sliced as:\n", + "# Elements from start to the end of the list\n", + "print(\"n[start:]\", n[start:]) #the : indicates slicing everything from start to the end\n", + "\n", + "# Elements from start to stop-1\n", + "print(\"n[start:stop]\", n[start:stop]) \n", + "\n", + "# Elements from the beginning to stop-1\n", + "print(\"n[:stop]\", n[:stop])\n", + "\n", + "# Copy of the whole list (alternative: list.copy())\n", + "print(\"n[:]\", n[:]) \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "As seen, the last one creates a copy. This can be useful when working with mutable objects. For example for copying a list to mutate the copy while keeping the original list unchanged.\n", + "\n", + "There is also a step mechanism. Continuing from above:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The list n: [3, 25, 83, 31, 14, 47, 1, 23, 57]\n", + "start index: 2\n", + "stop index: 6\n", + "step: 2\n", + "n[start:stop:step] [83, 14]\n" + ] + } + ], + "source": [ + "step = 2\n", + "\n", + "print(\"The list n:\", n)\n", + "print(\"start index:\", start)\n", + "print(\"stop index:\", stop)\n", + "print(\"step:\", step)\n", + "\n", + "# Extract from start to stop-1, by step\n", + "print(\"n[start:stop:step]\", n[start:stop:step]) \n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## List methods\n", + "Lists have many methods for performing common manipulations. Methods are recognized by the 'dot'-notation, so if a method was called `method_name()`, it would be used like `list.method_name()`.\n", + "\n", + "Suppose a list called `L` has been defined. Some of the most common list methods are:" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Initial list L: [10, 20, 30, 40]\n", + "Value to append: 50 with length 4\n", + "List L after append: [10, 20, 30, 40, 50] with length 5\n", + "List L after pop: [10, 20, 30, 40] with length 4\n", + "List L after reverse: [40, 30, 20, 10]\n" + ] + } + ], + "source": [ + "#create a list\n", + "L = [10, 20, 30, 40]\n", + "val = 50\n", + "\n", + "print(\"Initial list L:\", L)\n", + "print(\"Value to append:\", val, \" with length\", len(L))\n", + "\n", + "# Insert val at the end of L\n", + "L.append(val) \n", + "print(\"List L after append:\", L, \"with length\", len(L))\n", + "\n", + "# Remove i'th element from L and return it (if i is not provided, it defaults to last element)\n", + "L.pop() \n", + "print(\"List L after pop:\", L, \"with length\", len(L))\n", + "# Reverse all elements in list\n", + "L.reverse() \n", + "print(\"List L after reverse:\", L)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 1\n", + "Extract the last and first element from the list\n", + "~~~python\n", + "L1 = [10, 20, 30, 40, 50, 60]\n", + "~~~" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 2\n", + "Extract the following list from `L1` defined above by use of slicing.\n", + "\n", + "~~~python\n", + "[20, 30, 40]\n", + "~~~" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next [Module](./Module5-LoopsComprehension.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "p310env", + "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.10.19" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": { + "height": "168px", + "width": "267px" + }, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "165px" + }, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Exercises/Intro2Python/Module5-Dataframes.ipynb b/Exercises/Intro2Python/Module5-Dataframes.ipynb new file mode 100644 index 0000000..3084d50 --- /dev/null +++ b/Exercises/Intro2Python/Module5-Dataframes.ipynb @@ -0,0 +1,2002 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 5. Pandas DataFrames\n", + "Python is very good for data analysis. Much of this is thanks to the `pandas` library, which contains a wealth of powerful functions and methods to load and manipulate data.\n", + "\n", + "In the `pandas` environment what we normally refer to as a table is called a **DataFrame**. If the data has only a single column, it is called a **Series**. These are the core objects in the library.\n", + "\n", + "As with many libraries, there is a convention for renaming when importing. In `pandas` the convention is to import as `pd`: " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating a simple DataFrame\n", + "A simple DataFrame can be created with `pandas.DataFrame()`:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Column1Column2Column3
0112131
1122232
2132333
\n", + "
" + ], + "text/plain": [ + " Column1 Column2 Column3\n", + "0 11 21 31\n", + "1 12 22 32\n", + "2 13 23 33" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Create a simple DataFrame\n", + "df = pd.DataFrame({'Column1': [11, 12, 13], \n", + " 'Column2': [21, 22, 23], \n", + " 'Column3': [31, 32, 33]})\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ">**Note:**\n", + "> 1. The input argument for creating the DataFrame is a *dictionary*. I.e. a data structure with keys-value pairs which are enclosed in curly brackets `{}`.\n", + "> 2. It automatically creates an *index* column as the leftmost column. The index column defaults to be a counter starting from 0.\n", + "> 3. The displayed DataFrame looks nicer than the it would have in an editor. This is because it is styled with HTML in this notebook environment. In an editor, the printed DataFrame would look like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Column1 Column2 Column3\n", + "0 11 21 31\n", + "1 12 22 32\n", + "2 13 23 33\n" + ] + } + ], + "source": [ + "# DataFrame as it would look without HTML-styling\n", + "print(df)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Presenting results with DataFrames\n", + "If we have a dictionary from a previous calculation of some kind, we can quickly turn it into a DataFrame with the same pricinple as above: " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
N [kN]A [mm2]sigma_n [GPa]
0853140.270701
1563140.178344
21203140.382166
\n", + "
" + ], + "text/plain": [ + " N [kN] A [mm2] sigma_n [GPa]\n", + "0 85 314 0.270701\n", + "1 56 314 0.178344\n", + "2 120 314 0.382166" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Define normal forces and cross sectional areas\n", + "normal_forces = [85, 56, 120]\n", + "areas = [314, 314, 314]\n", + "\n", + "# Compute stress in cross section for all normal forces\n", + "stresses = [force/area for force, area in zip(normal_forces, areas)]\n", + "\n", + "# Gather calculation results in a dictionary \n", + "results = {'N [kN]': normal_forces, 'A [mm2]': areas, 'sigma_n [GPa]': stresses}\n", + "\n", + "# Create a DataFrame of the results form the dictionary\n", + "df2 = pd.DataFrame(results)\n", + "df2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Adjusting the index column\n", + "The default index (leftmost column) is not really suited for this particular scenario. It just sets the default counter starting from 0.\n", + "\n", + "We could change it to be `'Load Case'` and have it start at 1 instead of 0:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
N [kN]A [mm2]sigma_n [GPa]
Load Case
1853140.270701
2563140.178344
31203140.382166
\n", + "
" + ], + "text/plain": [ + " N [kN] A [mm2] sigma_n [GPa]\n", + "Load Case \n", + "1 85 314 0.270701\n", + "2 56 314 0.178344\n", + "3 120 314 0.382166" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Set the name of the index to 'Load Case'\n", + "df2.index.name = 'Load Case'\n", + "\n", + "# Add 1 to all indices\n", + "df2.index += 1\n", + "\n", + "df2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extracting a subset of data\n", + "We can extract specific columns from the DataFrame:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sigma_n [GPa]
Load Case
10.270701
20.178344
30.382166
\n", + "
" + ], + "text/plain": [ + " sigma_n [GPa]\n", + "Load Case \n", + "1 0.270701\n", + "2 0.178344\n", + "3 0.382166" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Extract only the stress column to new DataFrame\n", + "df2[['sigma_n [GPa]']]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> **Note:** The use of two square bracket pairs `[[]]` turns the result into a new DataFrame, with just one column. If there had been only a single square bracket, the result would be a *Series* object. See below." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Load Case\n", + "1 0.270701\n", + "2 0.178344\n", + "3 0.382166\n", + "Name: sigma_n [GPa], dtype: float64" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Extract stress column to Series object\n", + "df2['sigma_n [GPa]']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Most of the time, we want to keep working with DataFrames, so remember to put double square brackets.\n", + "\n", + "Double square brackets **must** be used if we want to extract more than one column. Otherwise, a `KeyError` will be raised." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
N [kN]sigma_n [GPa]
Load Case
1850.270701
2560.178344
31200.382166
\n", + "
" + ], + "text/plain": [ + " N [kN] sigma_n [GPa]\n", + "Load Case \n", + "1 85 0.270701\n", + "2 56 0.178344\n", + "3 120 0.382166" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Extract multiple columns to DataFrame\n", + "df2[['N [kN]', 'sigma_n [GPa]']]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Importing data from file to DataFrame\n", + "Data can be imported from various file types. The most common ones are probably standard text files (`.txt`), comma separated value files (`.csv`) or Excel files (`.xlsx`).\n", + "\n", + "Some common scenarios:\n", + "\n", + "-------\n", + "~~~python\n", + "# Import from .csv (comma separated values)\n", + "pd.read_csv('.csv')\n", + "\n", + "# Import from .txt with values separated by white space\n", + "pd.read_csv('.txt', delim_whitespace=True)\n", + "\n", + "# Import from Excel\n", + "pd.read_excel('.xlsx', sheet_name='')\n", + "~~~\n", + "---\n", + "\n", + "The above assumes that the files to import are located in the same directory as the script. Placing it there makes it easier to do the imports. If they are not in the same script the absolute or relative file path can be given as input.\n", + "\n", + "The functions above have many optional arguments. When importing from an Excel workbook it will often be necessary to specify more parameters than when importing a plain text file, because the Excel file inherently has a more complex structure. \n", + "For example, by default the data starts at cell A1 and the default sheet is the first sheet occurring in the workbook, but this is not always what is wanted.\n", + "\n", + "See docs for both functions here:\n", + "\n", + "* `panda.read_csv()`: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html\n", + "* `panda.read_excel()`: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_excel.html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import example" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A file called `HEA.txt` with properties for HEA steel profiles is located in the same directory as this notebook. Here's how to import it:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Profileh[mm]b[mm]Iy[mm4]Wel,y[mm3]g[kg/m]
0HE100A96100349000072.816.7
1HE120A1141206060000106.019.9
2HE140A13314010300000155.024.7
3HE160A15216016700000220.030.4
4HE180A17118025100000294.035.5
5HE200A19020036900000389.042.3
6HE220A21022054100000515.050.5
7HE240A23024077600000675.060.3
8HE260A250260104500000836.068.2
9HE280A2702801367000001010.076.4
10HE300A2903001826000001260.088.3
\n", + "
" + ], + "text/plain": [ + " Profile h[mm] b[mm] Iy[mm4] Wel,y[mm3] g[kg/m]\n", + "0 HE100A 96 100 3490000 72.8 16.7\n", + "1 HE120A 114 120 6060000 106.0 19.9\n", + "2 HE140A 133 140 10300000 155.0 24.7\n", + "3 HE160A 152 160 16700000 220.0 30.4\n", + "4 HE180A 171 180 25100000 294.0 35.5\n", + "5 HE200A 190 200 36900000 389.0 42.3\n", + "6 HE220A 210 220 54100000 515.0 50.5\n", + "7 HE240A 230 240 77600000 675.0 60.3\n", + "8 HE260A 250 260 104500000 836.0 68.2\n", + "9 HE280A 270 280 136700000 1010.0 76.4\n", + "10 HE300A 290 300 182600000 1260.0 88.3" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Import data from 'HEA.txt', which has data separated by white spaces\n", + "df = pd.read_csv('HEA.txt', delim_whitespace=True)\n", + "df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Filtering data\n", + "Data filtering is easy and intuitive. It is done by conditional expressions.\n", + "\n", + "For example, if we want to filter the HEA-DataFrame for profiles with moment of inertia $I_y$ larger than some value: " + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Profileh[mm]b[mm]Iy[mm4]Wel,y[mm3]g[kg/m]
5HE200A19020036900000389.042.3
6HE220A21022054100000515.050.5
7HE240A23024077600000675.060.3
8HE260A250260104500000836.068.2
9HE280A2702801367000001010.076.4
10HE300A2903001826000001260.088.3
\n", + "
" + ], + "text/plain": [ + " Profile h[mm] b[mm] Iy[mm4] Wel,y[mm3] g[kg/m]\n", + "5 HE200A 190 200 36900000 389.0 42.3\n", + "6 HE220A 210 220 54100000 515.0 50.5\n", + "7 HE240A 230 240 77600000 675.0 60.3\n", + "8 HE260A 250 260 104500000 836.0 68.2\n", + "9 HE280A 270 280 136700000 1010.0 76.4\n", + "10 HE300A 290 300 182600000 1260.0 88.3" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[df['Iy[mm4]'] > 30000000]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Understanding the filtering process\n", + "\n", + "The inner expression of the filtering\n", + "\n", + "~~~python\n", + "df['Iy[mm4]'] > 30000000\n", + "~~~\n", + "\n", + "returns the column `Iy[mm4]` from the DataFrame converted into a ***boolean Series***. I.e. a Series with `True`/`False` in each row depending on whether or not the condition is fulfilled:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 False\n", + "1 False\n", + "2 False\n", + "3 False\n", + "4 False\n", + "5 True\n", + "6 True\n", + "7 True\n", + "8 True\n", + "9 True\n", + "10 True\n", + "Name: Iy[mm4], dtype: bool" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Inner expression returns a boolean Series of the column Iy[mm4]\n", + "df['Iy[mm4]'] > 30000000" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This boolean Series is used to filter the original DataFrame, which is done in the outer expression by `df[boolean_series]`.\n", + "\n", + "The outer expression picks only the rows from the orignal DataFrame where the boolean series is `True`.\n", + "\n", + "## Filtering by multiple conditions\n", + "Filtering based on multiple conditions can be quite powerful. The syntax is only slightly more complicated:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Profileh[mm]b[mm]Iy[mm4]Wel,y[mm3]g[kg/m]
5HE200A19020036900000389.042.3
6HE220A21022054100000515.050.5
7HE240A23024077600000675.060.3
8HE260A250260104500000836.068.2
\n", + "
" + ], + "text/plain": [ + " Profile h[mm] b[mm] Iy[mm4] Wel,y[mm3] g[kg/m]\n", + "5 HE200A 190 200 36900000 389.0 42.3\n", + "6 HE220A 210 220 54100000 515.0 50.5\n", + "7 HE240A 230 240 77600000 675.0 60.3\n", + "8 HE260A 250 260 104500000 836.0 68.2" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[(df['Iy[mm4]'] > 30000000) & (df['h[mm]'] < 260 )]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each condition must be inside parentheses `()` and conditions are separated by `&`.\n", + "\n", + "---\n", + "\n", + "Filtering can also be based on lists of values. Consider the code below which extracts rows where \n", + "\n", + "* Moment of inertia $I_y$ is larger than some value \n", + "* The profile name is present in the list called `valid_profiles`" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Profileh[mm]b[mm]Iy[mm4]Wel,y[mm3]g[kg/m]
6HE220A21022054100000515.050.5
8HE260A250260104500000836.068.2
9HE280A2702801367000001010.076.4
\n", + "
" + ], + "text/plain": [ + " Profile h[mm] b[mm] Iy[mm4] Wel,y[mm3] g[kg/m]\n", + "6 HE220A 210 220 54100000 515.0 50.5\n", + "8 HE260A 250 260 104500000 836.0 68.2\n", + "9 HE280A 270 280 136700000 1010.0 76.4" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Valid profiles to choose from\n", + "valid_profiles = ['HE180A', 'HE220A', 'HE260A', 'HE280A']\n", + "\n", + "# Filter DataFrame based on Iy value and valid profiles\n", + "df[(df['Iy[mm4]'] > 30000000) & (df['Profile'].isin(valid_profiles) )]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + "If we instead want to rule the profiles in the list, we could put a `~` in front of the condition to specify that values must ***not*** be present in the list:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Profileh[mm]b[mm]Iy[mm4]Wel,y[mm3]g[kg/m]
5HE200A19020036900000389.042.3
7HE240A23024077600000675.060.3
10HE300A2903001826000001260.088.3
\n", + "
" + ], + "text/plain": [ + " Profile h[mm] b[mm] Iy[mm4] Wel,y[mm3] g[kg/m]\n", + "5 HE200A 190 200 36900000 389.0 42.3\n", + "7 HE240A 230 240 77600000 675.0 60.3\n", + "10 HE300A 290 300 182600000 1260.0 88.3" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Invalid profiles\n", + "invalid_profiles = ['HE180A', 'HE220A', 'HE260A', 'HE280A']\n", + "\n", + "# Filter DataFrame based in Iy and valid profiles\n", + "df[(df['Iy[mm4]'] > 30000000) & (~df['Profile'].isin(invalid_profiles) )]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exporting a DataFrame to a file\n", + "Exporting a DataFrame to a new text file could not be easier. Saving to a `.txt`:\n", + "\n", + "---\n", + "~~~python\n", + "# Save df to a .txt file in the same folder as the script\n", + "df.to_csv('filename.txt')\n", + "~~~\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## GroupBy\n", + "The method `groupby` provides a way to **split** a DataFrame into groups based on some condition, **apply** a function to those groups and **combine** the results into a new DataFrame that is then returned.\n", + "\n", + "\n", + "### An example" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
FruitAmount_sold
0Pear3
1Apple6
2Apple7
3Banana2
4Lemon4
5Banana7
6Banana1
7Pear6
\n", + "
" + ], + "text/plain": [ + " Fruit Amount_sold\n", + "0 Pear 3\n", + "1 Apple 6\n", + "2 Apple 7\n", + "3 Banana 2\n", + "4 Lemon 4\n", + "5 Banana 7\n", + "6 Banana 1\n", + "7 Pear 6" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Create a dataframe to work with\n", + "dff = pd.DataFrame({'Fruit': ['Pear', 'Apple', 'Apple', 'Banana', \n", + " 'Lemon', 'Banana', 'Banana', 'Pear'], \n", + " 'Amount_sold': [3, 6, 7, 2, 4, 7, 1, 6]})\n", + "dff" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `DataFrame.groupby` method itself returns a *groupby object*, **not** a DataFrame. So printing that on its own will just show you the object, which is not very helpful: " + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# The gropuby will return a groupby object\n", + "dff.groupby('Fruit')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The object contains metadata about how the data is grouped. It's kind of an intermediate state where the object is ready to receive a function.\n", + "\n", + "The powerful operations are visible only after we apply a certain function to the groupby object, like `sum()`: " + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Amount_sold
Fruit
Apple13
Banana10
Lemon4
Pear9
\n", + "
" + ], + "text/plain": [ + " Amount_sold\n", + "Fruit \n", + "Apple 13\n", + "Banana 10\n", + "Lemon 4\n", + "Pear 9" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dff.groupby('Fruit').sum()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We could say that we first **split** the DataFrame in fruit groups, **applied** a function to those individual groups and **combined** and returned the results as a new DataFrame. \n", + "\n", + "Note that by default the column that the data was grouped by becomes the new index, since these are now unique values." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "heading_collapsed": true + }, + "source": [ + "### Documentation\n", + "Documentation for `groupby`: http://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.groupby.html\n", + "Documentation for `apply`: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Printing with `df.head()` and `df.tail()` \n", + "When DataFrames become very large, printing all the data to the screen becomes unwieldy. Printing is mostly done only to make sure that some operation worked as we expected it would. In that case, printing just a few rows will be sufficient, which the following methods will allow for:\n", + "\n", + "---\n", + "~~~python\n", + "# Print the first 5 rows of df\n", + "df.head()\n", + "\n", + "# Print the last 5 rows of df\n", + "df.tail()\n", + "\n", + "# Print the first x rows of df\n", + "df.head(x)\n", + "\n", + "# Print the last y rows of df\n", + "df.tail(y)\n", + "~~~\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Something to be aware of\n", + "A potentially confusing thing about `pandas` methods is that it can be hard to know which ones mutates the DataFrame *inplace* and which ones need to be saved to a new variable. \n", + "\n", + "Consider the lines below:\n", + "\n", + "---\n", + "~~~python\n", + "# This line does not rename the column in df but returns a copy of df with the column renamed\n", + "df.rename(columns={'Current_name': 'New_name}) \n", + " \n", + "# Thus, it has to be saved to a new variable\n", + "df = df.rename(columns={'Current_name': 'New_name}) \n", + " \n", + "# Or, use the argument inplace=True to modify df directly\n", + "df.rename(columns={'Current_name': 'New_name'}, inplace=True) \n", + "~~~\n", + "---\n", + "\n", + "You will most likely stumble upon this when working with `pandas`. \n", + "\n", + "***Note that there is no error when when executing the first line shown above, but when `df` is eventually printed it will just not show up as intended.***" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "## Much more functionality\n", + "There are numerous functions and methods available in `pandas` and the above mentioned barely scrathes the surface. \n", + "\n", + "Practically anything that you would want to do to a dataset can be done. And quite possibly somebody has had the same problem as you before and found a solution or maybe even even contributed to the `pandas` library and put in that functionality for everyone to use.\n", + "However, some functionality can be much harder to understand and use than the above mentioned.\n", + "\n", + "The `pandas` library integrates well with other big libraries like `numpy` and `matplotlib` and other functionality in the Python language in general. For example, many DataFrame methods can take a customized function as input `def ...()` and run it through certain content of the DataFrame.\n", + "\n", + "Plotting with `matplotlib` is directly supported in `pandas` via shortcuts so you can do `df.plot()` and it will create a plot of the DataFrame of a specified kind even without having to import `matplotlib`.\n", + "\n", + "## When and why to use `pandas`\n", + "* The manipulations that can be done with `pandas` are quite powerful when datasets become much larger than ones shown above. It is especially helpful when the dataset reaches a size where all data can not be viewed and understood well by simply scrolling down and looking at the data. If the number of rows go beyond just a couple of thousands, it is hard to get the overall feel for the data and its trends just by inspection. This is were typing logic commands to do manipulations becomes a great help. \n", + "\n", + "\n", + "* Use it when a very specific solution for data manipulation is desired. Especially when the solution is not trivially done in for example Excel.\n", + "\n", + "\n", + "* It is a good tool for combining multiple datasets, e.g. from different files.\n", + "\n", + "\n", + "* Last but not least, it is good for reproducibility and handling changes in data size. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 1.1\n", + "***All exercises 1.x are working with the same DataFrame.***\n", + "\n", + "---\n", + "\n", + "Create a DataFrame from the dictionary `d` below. Save it is a variable called `df`.\n", + "\n", + "---\n", + "~~~python \n", + "# Import built-in libraries string and random \n", + "import random\n", + "import string\n", + "\n", + "# Get upper- and lowercase letters from the string library\n", + "lower = string.ascii_lowercase\n", + "upper = string.ascii_uppercase\n", + "\n", + "# Create a dictionary with dummy data of integers and letters\n", + "d = {'Integers': [random.randint(1, 100) for i in range(1, 100)],\n", + " 'Lowercase': [random.choice(lower) for i in range(1, 100)],\n", + " 'Uppercase': [random.choice(upper) for i in range(1, 100)]}\n", + "~~~\n", + "---\n", + "\n", + "Print/display the entire DataFrame to see if it comes out as you expect.\n", + "\n", + "Remember to `import pandas as pd`.\n", + "\n", + "# Exercise 1.2\n", + "Print/display the only the first or last rows by using `DataFrame.head()` or `DataFrame.tail()`. You choose how many rows to print (default is 5).\n", + "\n", + "*Use these methods to test print the DataFrames from now on to avoid printing all rows.*\n", + "\n", + "# Exercise 1.3\n", + "Filter `df` to only contain the rows where the uppercase letter is `'K'`. Save it to a new variable called `dfk`.\n", + "\n", + "Print/display it to make sure it is correct.\n", + "\n", + "*If you were unlucky and did not have a `'K'` generated in the uppercase column, try re-running the code (it chooses letters at random)*.\n", + "\n", + "\n", + "# Exercise 1.4\n", + "When printing the filtered `dfk`, notice that the index from the original DataFrame is kept. This is often useful for back reference, but sometimes we want the index to be reset. \n", + "\n", + "Reset the index of `dfk` to start from 0 by using `DataFrame.reset_index()`. \n", + "This method does not modify the DataFrame inplace by default, so remember to either save to a new variable or give the input argument `inplace=True`.\n", + "\n", + "By default, the orignal index will be added as a new column to the DataFrame. If you don't want this, use the input argument `drop=True`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 2.1\n", + "***All exercises 2.x are to be seen as the same problem. It has just been divided into smaller tasks.***\n", + "\n", + "---\n", + "This exercise works with a file called `shear_key_forces.csv`. To get the file go [here](https://raw.githubusercontent.com/Python-Crash-Course/Python101/master/Session%205%20-%20Dataframes/shear_key_forces.csv), right-click and choose \"save as\". Select `.csv` as file format. Save the file in the same folder as your script for this exercise. \n", + "\n", + "Inside your script, import the file `shear_key_forces.csv` to a DataFrame using `pandas.read_csv()`. The values in the file are comma separated, which the function also assumes as default. \n", + "The file has 104329 rows. Print the head or the tail to see the imported data.\n", + "\n", + "*The data has all spring element forces in a bunch of load cases from a Sofistik finite element calculation. It's not strictly necessary to know what the data represents. It could just be looked at as dummy data to work with.*\n", + "\n", + "\n", + "# Exercise 2.2\n", + "*The model has many spring elements. Some of them represent shear keys between the structural parts of a tunnel at movement joint locations. These are the ones we are going to extract.*\n", + "\n", + "The data has a column `'shear_key'` which has the name of the shear key if the element in that row is part of a shear key in the model. E.g. `'Shear_key1'`. If the element is not part of a shear key, the name is `'Not_a_shear_key'`.\n", + "\n", + "Filter out all rows which are not part of a shear key. The resulting DataFrame should have 2874 rows. \n", + "\n", + "\n", + "# Exercise 2.3\n", + "Since we are not really using the column called `'Element_no'`, go ahead and remove it from the DataFrame. This can be done by\n", + "\n", + "---\n", + "~~~python \n", + "# Remove column 'column_name' form 'df'\n", + "df = df.drop('column_name', axis=1)\n", + "~~~\n", + "---\n", + "The argument `axis=1` specifies that it is a column that should be removed, whereas `axis=0` would represent removal of a row.\n", + "\n", + "*Remember to save to a new variable or use argument `inplace=True`. If you save to a variable, you can use the same name to 'overwrite' the old one if it's not needed anymore.*\n", + "\n", + "\n", + "# Exercise 2.4\n", + "*Each shear key consists of three spring elements. The total force in the shear key is the sum of those three spring forces.*\n", + "\n", + "Create a DataFrame with the sum of the three values within each shear key for every load case. The resulting DataFrame should have 958 rows.\n", + "\n", + "\n", + "**Hint:** Use the methods `DataFrame.groupby()` and `DataFrame.sum()` like this:\n", + "\n", + "~~~python\n", + "df.groupby(['Shear_key', 'LC', 'LC-title'], as_index=False).sum()\n", + "~~~\n", + "Replace `df` with the name of your variable containing the DataFrame.\n", + "\n", + "Here, a list of column labels is passed in the `groupby()` method instead of just a single column label. The first column `'Shear_key'` is what is used to create the groups, while consecutive labels just follow. Any columns that are not passed in will not appear in the resulting DataFrame. \n", + "\n", + "# Exercise 2.5\n", + "Filter the DataFrame for a specific shear key, for example `'Shear_key1'` and create a bar plot of it with the `DataFrame.plot()` method. The bar plot should have the load cases as $x$-values and the force $P$ [kN] as $y$-values.\n", + "\n", + "---\n", + "~~~python\n", + "# Plot dataframe contents\n", + "df.plot(kind='bar', x='column_for_x_values', y='column_for_y_values')\n", + "~~~\n", + "---\n", + "\n", + "The method has many optional arguments, see https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.plot.html.\n", + "\n", + "Try for example to change the figure size by `figsize=(width, height)`, rotate the x-ticks by `rot=angle_in_degrees` and change the color of the bars by `color='some_color'`.\n", + "\n", + "# If you are up for more\n", + "Create a loop that goes through all shear keys, creates a plot like the one from the previous exercise and saves each plot to a png-file.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# End of exercises\n", + "\n", + "*The cell below is for setting the style of this document. It's not part of the exercises.*" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import HTML\n", + "HTML(''.format(open('../css/cowi.css').read()))" + ] + } + ], + "metadata": { + "hide_input": false, + "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" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Table of Contents", + "toc_cell": false, + "toc_position": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "391.997px" + }, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Exercises/Intro2Python/Module5-LoopsComprehension.ipynb b/Exercises/Intro2Python/Module5-LoopsComprehension.ipynb new file mode 100644 index 0000000..b5a4d26 --- /dev/null +++ b/Exercises/Intro2Python/Module5-LoopsComprehension.ipynb @@ -0,0 +1,633 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `for` loops\n", + "The general syntax in a `for` loop is\n", + " \n", + "### Syntax of `for`-loops\n", + " \n", + "~~~python\n", + "for item in iterable:\n", + " # Code goes here (must be indented!)\n", + "~~~\n", + "\n", + "\n", + "\n", + "\n", + "Recall that an `iterable` is a fancy word for something that can be iterated over. Like strings, lists, tuples etc.\n", + "\n", + "So, printing numbers from 0-5 can be done like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n" + ] + } + ], + "source": [ + "# Printing numbers from 0-5\n", + "for num in [0, 1, 2, 3, 4, 5]: #num is the loop variable, it can be any name\n", + " print(num)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "> **Remember:** All code inside a `for`-block must be indented!\n", + "\n", + "A common way of quickly generating the numbers from 0-5 instead of typing the list `[0, 1, 2, 3, 4, 5]` is by the `range()` function, which has two forms:\n", + "\n", + "~~~python\n", + " range(stop) # Generates numbers from 0 to stop-1\n", + "~~~\n", + "\n", + "~~~python\n", + " range(start, stop[, step]) # Generates numbers from start to stop-1 (step is optional) \n", + "~~~" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "4\n", + "9\n", + "16\n", + "25\n", + "the range list is : [0, 1, 2, 3, 4, 5]\n" + ] + } + ], + "source": [ + "# Printing square of numbers from 0-5\n", + "for num in range(6):\n", + " print(num**2) #print square of num\n", + " \n", + "print(\"the range list is :\", list(range(6)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is an example where each element of a list of strings is accessed in turn and named `string`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SNOTEL\n", + "Streamflow monitoring\n", + "CIROH\n", + "CUAHSI\n" + ] + } + ], + "source": [ + "strings = ['SNOTEL', 'USGS', 'NRCS', 'NOAA', 'Streamflow monitoring', 'NWS', 'CIROH', 'CUAHSI'] #list of strings\n", + "\n", + "for s in strings: # This would be like saying: for each string in the list strings\n", + " if len(s) >= 5: # Condition: If the current string has more or equal to five characters , change this to other: greater than, less than, does not equal to, etc.\n", + " print(s) # Print it" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how for-loops in Python can avoid dealing with indexes, while still supporting the alternative." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SNOTEL\n", + "Streamflow monitoring\n", + "NWS\n", + "CIROH\n", + "CUAHSI\n" + ] + } + ], + "source": [ + "# Using enumerate to also gain access to the running index\n", + "for i, s in enumerate(strings): #the i is the index, s is the current string\n", + " if len(strings[i]) !=4: # If the string length is not equal to 4\n", + " print(strings[i]) # Print it" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `while` loops\n", + "A `while` loop is a loop that continues until some condition is no longer satisfied.\n", + " \n", + "### Syntax of `while`-loops \n", + "~~~python\n", + "while condition: \n", + " # Code goes here (must be indented!)\n", + "~~~\n", + "\n", + "Where evaluation of `condition` must return a boolean (`True` or `False`).\n", + "\n", + "\n", + "\n", + "There must be some kind of change in `condition` for every loop. If there isn't, the loop becomes an **infinite loop** and runs forever (or until you stop it). \n", + "\n", + "**An example of an infinite loop is**\n", + "\n", + "~~~~python\n", + "counter = 0\n", + "while counter < 3: \n", + " print(counter) # The variable counter is never updated. 0 < 3 is always True => prints forever\n", + "~~~~\n", + "\n", + "**The counter should be updated within the loop**, e.g. like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The count is 1\n", + "The count is 2\n", + "The count is 3\n", + "The count is 4\n" + ] + } + ], + "source": [ + "counter = 1 # Initialize counter variable\n", + "while counter < 5: # Continue while counter is less than 5\n", + " print(f'The count is {counter}') #print count\n", + " counter += 1 # Update counter (equivalent to: counter=counter+1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "\n", + " > **Remember:** All code inside a `while`-block must be indented!\n", + "\n", + "A `while`-loop can be good when the number of iterations are unknown beforehand. This could be when searching for a root of an equation.\n", + "\n", + "When iterating, convergence is not always guaranteed. A common way of exiting the `while`-loop is to define a max number of iterations and then check in each loop whether this number has been reached. If it has, then the loop should `break`.\n", + "\n", + "A similar logic to `while`-loops could be done with by `for`-loops, but a `while`-loop is cleaner for some purposes and can help to clarify the intent of the code." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Both for and while loops can be affected by `continue` and/or `break`. `Continue` starts on the next interation while skipping the rest of the code block and `break` stops the whole loop. The example above is reproduced below using `break`. This can sometime yield more readable code." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The count is 1\n", + "The count is 2\n", + "The count is 3\n", + "The count is 4\n" + ] + } + ], + "source": [ + "counter = 1 # Initialize counter variable\n", + "while True: # Continue indefinitely\n", + " print(f'The count is {counter}') #print count\n", + " counter += 1 # Update counter (equivalent to: counter=counter+1)\n", + " if counter > 4: # add if statement to check counter, here we want to stop when counter is greater than 4\n", + " break # break out of while loop" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## List comprehensions\n", + "List comprehensions are another way of writing `for`-loops in a single line of code. They're generally faster and can be used for more compact representation of simple interations yielding more readable code.\n", + "\n", + "### General form of list comprehensions\n", + "The general form of the simplest list comprehension is\n", + "~~~~python\n", + " result_list = [expression for item in iterable]\n", + "~~~~\n", + "\n", + "\n", + "* iterable is a sequence that can be iterated over, this could be a list, a string, a tuple etc. \n", + "* item is the counter for the iterable, think of this as the i'th element \n", + "* expression can be anything, but will often include the item\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A basic example for multiplying all elements by 2:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[24, 430, 62, 874, 102]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Define a list (iterable)\n", + "L1 = [12, 215, 31, 437, 51]\n", + "\n", + "# List comprehension to multiply each element of L1 by 2\n", + "L2 = [2*elem for elem in L1] #the expression is 2*elem, for each elem in L1\n", + "L2" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[24, 430, 62, 874, 102]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#make the above list comprehension into a for loop\n", + "L2 = [] #initialize empty list\n", + "for elem in L1: #for each element in L1\n", + " L2.append(2*elem) #append 2*elem to L2\n", + "L2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that `2 * L1` will not create the same output, but instead repeat the list as seen below." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[12, 215, 31, 437, 51, 12, 215, 31, 437, 51]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "2 * L1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "List comprehension is significantly faster than a for loop, and the preferred method for executing code, where possible." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Time taken using for loop: 0.084145 seconds\n", + "Time taken using list comprehension: 0.054910 seconds\n", + "Are both methods producing the same result? True\n", + "List comprehension is 1.53 times faster than for loop.\n" + ] + } + ], + "source": [ + "# An example of the speed difference between a for loop and list comprehension\n", + "import time #import time module to measure execution time\n", + "# Define a list (iterable)\n", + "L1 = list(range(1, 1000001)) # List of integers from 1 to 1,000,000\n", + "# Using a for loop to create a new list with each element multiplied by 2\n", + "start_time = time.time() #start timer\n", + "L2_loop = [] #empty list to store results\n", + "for elem in L1: #loop through each element in L1\n", + " L2_loop.append(2 * elem) #multiply element by 2 and append to L2_loop\n", + "end_time = time.time() #end timer\n", + "forlooptime = end_time - start_time #calculate time taken, assign to forlooptime variable\n", + "print(f\"Time taken using for loop: {forlooptime:.6f} seconds\") \n", + "\n", + "# Using list comprehension to create a new list with each element multiplied by 2\n", + "start_time = time.time() #start timer\n", + "L2_comp = [2 * elem for elem in L1] #list comprehension, not how much less space it takes\n", + "end_time = time.time() #end timer\n", + "comptime = end_time - start_time #calculate time taken, assign to comptime variable\n", + "print(f\"Time taken using list comprehension: {comptime:.6f} seconds\") \n", + "print(\"Are both methods producing the same result?\", L2_loop == L2_comp)\n", + "print(f\"List comprehension is {(forlooptime)/(comptime):.2f} times faster than for loop.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To get a vectorized behavior like that we could have used a `NumPy` array. Later sessions will explore `NumPy` further." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### List comprehension with `if`-`else`-statement\n", + " \n", + "~~~~python\n", + " result_list = [expression1 if condition else expression2 for item in iterable]\n", + "~~~~\n", + "\n", + "* `iterable` is a sequence that can be iterated over, this could be a list, a string, a tuple etc. \n", + "\n", + "* `condition` is a logical condition, e.g. `item > 3`, which returns a boolean (`True`/`False`). This can act as as filter.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[None, None, 182, None, 151, 174]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Define a list (iterable)\n", + "v = [3, 62, 182, 26, 151, 174]\n", + "\n", + "# Set all elements of v that are less than 100 equal to 0\n", + "w = [None if x < 100 else x for x in v]\n", + "w" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[None, None, 182, None, 151, 174]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#the above list comprehension as a for loop\n", + "w = [] #initialize empty list\n", + "for x in v: #for each element in v\n", + " if x < 100: #check if element is less than 100\n", + " w.append(None) #append None to w\n", + " else:\n", + " w.append(x) #append x to w\n", + "w" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "### Benefits of list comprehensions\n", + "List comprehensions can be done in one line and are often cleaner and more readable for simple iteration. \n", + "They are also generally computationally faster than regular `for`-loops and also faster to type." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 1\n", + "Given the list\n", + "\n", + "~~~python\n", + "n = [23, 73, 12, 84]\n", + "~~~\n", + "\n", + "\n", + "Create a `for` loop that prints:\n", + "\n", + "~~~python\n", + "'23 sqaured is 529'\n", + "'73 sqaured is 5329'\n", + "'12 sqaured is 144'\n", + "'84 sqaured is 7056'\n", + "~~~\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 2\n", + "Use a list comprehension to create a new list with areas of the circles that have diameters defined by\n", + "\n", + "~~~python\n", + "diameters = [10, 12, 16, 20, 25, 32]\n", + "~~~" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 3\n", + "From the following list, create a new list containing only the elements that have exactly five characters. \n", + "~~~python\n", + "phonetic_alphabet = ['Alpha', 'Bravo', 'Charlie', 'Delta', 'Echo', 'Foxtrot']\n", + "~~~" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next [Module](./Module6-Functions.ipynb)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "p310env", + "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.10.19" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": { + "height": "168px", + "width": "267px" + }, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "165px" + }, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Exercises/Intro2Python/Module6-Functions.ipynb b/Exercises/Intro2Python/Module6-Functions.ipynb new file mode 100644 index 0000000..783cb56 --- /dev/null +++ b/Exercises/Intro2Python/Module6-Functions.ipynb @@ -0,0 +1,559 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "cell_style": "center" + }, + "source": [ + "\n", + "# Functions\n", + "A **function** is a block of code that is first defined, and thereafter can be called to run as many times as needed. A function might have arguments, some of which can be optional if a default value is specified.\n", + "\n", + "A function is called by parentheses: `function_name()`. Arguments are placed inside the parentehes and comma separated if there are more than one.\n", + "Similar to `f(x, y)` from mathematics.\n", + "\n", + "A function can return one or more values to the caller. The values to return are put in the `return` statement. When the code hits a `return` statement the function terminates. If no `return` statement is given, the function will return `None`.\n", + "\n", + "The general syntax of a function is:\n", + "\n", + "~~~python\n", + "def function_name(arg1, arg2, default_arg1=0, default_arg2=None):\n", + " '''This is the docstring \n", + " \n", + " The docstring explains what the function does, so it is like a multiline comment. It does not have to be here, \n", + " but it is good practice to use them to document the code. They are especially useful for more complicated \n", + " functions, although functions should in general be kept as simple as possible.\n", + " Arguments could be explained together with their types (e.g. strings, lists, dicts etc.).\n", + " '''\n", + " \n", + " # Function code goes here\n", + " \n", + " # Possible 'return' statement terminating the function. If 'return' is not specified, function returns None.\n", + " return return_val1, return_val2\n", + "~~~\n", + "\n", + "If multiple values are to be returned, they can be separated by commas as shown. The returned entity will by default be a `tuple`.\n", + "\n", + "Note that when using default arguments, it is good practice to only use immutable types. An example further below will demonstrate why this is recommended. \n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic functions\n", + "A simple function with one argument is defined below." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# Make a function\n", + "def f(x): #initiate a function f with parameter x\n", + " return 6.25 + x + x**2 #return the value of the expression 6.25 + x + x squared" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + ">**Note:** No code has been executed yet. It has merely been defined so it's ready to run when the function is called.\n", + "\n", + "Calling the function with the argument `5` returns:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "36.25" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "f(5) #call the function f with an argument of 5, try other numbers, assign to variables, etc." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we define a function without returning anything, it returns `None`:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n" + ] + } + ], + "source": [ + "def first_char(word): #initiate a function first_char with parameter word\n", + " word[0] # <--- No return statement, function returns None\n", + " \n", + " \n", + "# Variable a will be equal to None\n", + "a = first_char('streamflow') \n", + "\n", + "# Printing the returned value\n", + "print(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Often a return value is wanted from a function, but there could be scenarios where it is not wanted. E.g. if you want to mutate a list by the function. Consider this example:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello Streamflow Joe\n", + "Hello Streamflow Joe\n", + "None\n" + ] + } + ], + "source": [ + "#create a function that says hello to the input name\n", + "def say_hello_to(name): #initiate function say_hello_to with parameter name\n", + " ''' Say hello to the input name '''\n", + " print(f'Hello {name}') #print 'Hello {name}' where {name} is the input parameter\n", + " \n", + "\n", + "say_hello_to('Streamflow Joe') # <--- Calling the function prints 'Hello {name}'\n", + "\n", + "r = say_hello_to('Streamflow Joe') # <--- Calling the function prints 'Hello {name}' and assigns None to r\n", + "\n", + "print(r) # <--- Prints None, since function had no return statement " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The function was still useful even though it did not return anything. Another example could be a function that creates a plot instead of returning a value.\n", + "\n", + "## Engineering functions\n", + "\n", + "How can we make a simple function to estimate streamflow?" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "#make a Mannings equation function that takes in channel width, depth, slope, and mannings coefficient and returns flow rate Q, cfs\n", + "def mannings_equation_rect(width, depth, slope, n=0.03): #initiate function mannings_equation with parameters width, depth, slope, and n (default value 0.03)\n", + " ''' Calculate flow rate Q using Manning's equation for a rectangular channel '''\n", + " A = width * depth #cross-sectional area in sqft\n", + " P = width + 2 * depth #wetted perimeter in ft\n", + " R = A / P #hydraulic radius in ft\n", + " Q = (1.486/n) * A * R**(2/3) * slope**0.5 #Manning's equation, notice how the order of opperations is handled by parentheses\n", + " return Q #return flow rate Q, cfs" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Flow rate Q: 20359.95 cfs\n" + ] + } + ], + "source": [ + "width = 100 #channel width in ft\n", + "depth = 10 #channel depth in ft\n", + "slope = 0.01 #channel slope in ft/ft\n", + "\n", + "Q = mannings_equation_rect(width, depth, slope) #call mannings_equation_rect function with width, depth, slope, and default n value\n", + "print(f'Flow rate Q: {Q:.2f} cfs') #print" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Examples of built-in functions\n", + "### Using `enumerate` for looping in index/value pairs\n", + "The built-in `enumerate` is useful when you want to loop over an iterable together with the index of each of its elements:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 C\n", + "1 i\n", + "2 r\n", + "3 o\n", + "4 h\n" + ] + } + ], + "source": [ + "# Define a list of strings\n", + "letters = ['C', 'i', 'r', 'o', 'h']\n", + "\n", + "# Loop over index and elements in pairs\n", + "for idx, letter in enumerate(letters): #loop through the enumerated letters list, getting both index and letter\n", + " print(idx, letter)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 C\n", + "2 i\n", + "3 r\n", + "4 o\n", + "5 h\n" + ] + } + ], + "source": [ + "# Starting at 1 (internally, enumerate has start=0 set as default)\n", + "for idx, letter in enumerate(letters, start=1): #loop through the enumerated letters list starting index at 1\n", + " print(idx, letter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`enumerate` solves a commonly encountered scenario, i.e. looping in index/value pairs. \n", + "\n", + "Similar functionality could be obtained by looping over the index and indexing the list value inside each loop." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 C\n", + "1 i\n", + "2 r\n", + "3 o\n", + "4 h\n" + ] + } + ], + "source": [ + "# Loop over index and elements in pairs\n", + "for i in range(len(letters)): #loop through a range object created from the length of the letters list\n", + " print(i, letters[i])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Pythonic way is to use `enumerate` in this scenario since most people find it more readable. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using `zip` for looping over multiple iterables\n", + "The built-in `zip`is useful when you want to put two lists up beside each other and loop over them element by element in pairs." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10 78.5\n", + "12 113.04\n", + "16 200.96\n", + "20 314.0\n", + "25 490.625\n" + ] + } + ], + "source": [ + "# Define a list of pipe diameters\n", + "diameters = [10, 12, 16, 20, 25] \n", + "\n", + "# Compute the flow area by list comprehension\n", + "areas = [3.14 * (d/2)**2 for d in diameters] #multiply 3.14 by (d/2) squared for each diameter d in the diameters list\n", + "\n", + "# Print (diameter, area) pairs\n", + "for d, A in zip(diameters, areas): #loop through pairs of diameters and areas using zip, zip combines two lists into pairs\n", + " print(d, A)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Local vs. global variables\n", + "\n", + "* **Global variables**: Variables defined outside a function\n", + "* **Local variables**: Variables defined inside a function\n", + "\n", + "Local variables cannot be accessed outside the function. By returning a local variable and saving it into a global variable we can use the result outside the function, in the global namespace." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "def mannings_equation_rect(width, depth, slope): #initiate function mannings_equation with parameters width, depth, slope\n", + " ''' Calculate flow rate Q using Manning's equation for a rectangular channel '''\n", + " A = width * depth #cross-sectional flow area in sqft\n", + " P = width + 2 * depth #wetted perimeter in ft\n", + " R = A / P #hydraulic radius in ft\n", + " Q = (1.486/n) * A * R**(2/3) * slope**0.5 #Manning's equation using global n\n", + " return Q #return flow rate Q, cfs" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "mannings_equation_rect() takes 3 positional arguments but 4 were given", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[12], line 4\u001b[0m\n\u001b[1;32m 2\u001b[0m width, depth, slope \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m10\u001b[39m, \u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m0.01\u001b[39m \u001b[38;5;66;03m#channel width in ft, channel depth in ft, channel slope in ft/ft\u001b[39;00m\n\u001b[1;32m 3\u001b[0m n \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m0.02\u001b[39m \u001b[38;5;66;03m#global variable n\u001b[39;00m\n\u001b[0;32m----> 4\u001b[0m Q \u001b[38;5;241m=\u001b[39m \u001b[43mmannings_equation_rect\u001b[49m\u001b[43m(\u001b[49m\u001b[43mwidth\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdepth\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mslope\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mn\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m#initiate function mannings_equation with parameters width, depth, slope, n\u001b[39;00m\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mFlow rate Q: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mQ\u001b[38;5;132;01m:\u001b[39;00m\u001b[38;5;124m.2f\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m cfs\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mArea: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mA\u001b[38;5;132;01m:\u001b[39;00m\u001b[38;5;124m.2f\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m sqft\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;66;03m#this shoould give an error since A is a local variable inside the function, why do we get a value?\u001b[39;00m\n", + "\u001b[0;31mTypeError\u001b[0m: mannings_equation_rect() takes 3 positional arguments but 4 were given" + ] + } + ], + "source": [ + "#lets go back to our mannings equation function to see local vs global variables\n", + "width, depth, slope = 10, 1, 0.01 #channel width in ft, channel depth in ft, channel slope in ft/ft\n", + "n = 0.02 #global variable n\n", + "Q = mannings_equation_rect(width, depth, slope, n) #initiate function mannings_equation with parameters width, depth, slope, n\n", + "\n", + "print(f'Flow rate Q: {Q:.2f} cfs')\n", + "print(f'Area: {A:.2f} sqft') #this shoould give an error since A is a local variable inside the function, why do we get a value?\n", + "print(f'R: {R:.2f} ft') #this will give an error since R is a local variable inside the function\n", + "print(f'Perimeter: {P:.2f} ft') #this will give an error since P is a local variable inside the function\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports\n", + "\n", + "### Libraries\n", + "A quick overview of imports of libraries in Python, here shown for the math library:\n", + "\n", + "---\n", + "~~~python\n", + "import math # Lets you access everything in the math library by dot-notation (e.g math.pi) \n", + "from math import pi # Lets you use pi directly\n", + "~~~\n", + "\n", + "### Your own modules\n", + "You can also import your own `.py` files this way and access the functions inside them. It is easiest if the file to import is located in the same folder as the `.py` file you want to import to. \n", + "\n", + "An example:\n", + "\n", + "~~~python\n", + "import my_module # my_module could be your own python file located in same directory\n", + "~~~\n", + "If you have a function inside `my_module` called `my_func`, you can now call it as `my_module.my_func()`.\n", + "\n", + "> Python files that are meant to be executed directly are called **scripts** and files that are imported into other files are called **modules**." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 1\n", + "Finish the function below that takes a radius `r` as input and make it return the circle area.\n", + "\n", + "~~~python\n", + "def circle_area(r):\n", + " '''Return circle area'''\n", + " # Your code goes here\n", + "~~~\n", + "\n", + "Try to call it to see if it works. If you want to access `pi` to avoid typing it out yourself, put the line `from math import pi` at some point before defining the `circle_area` function.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 2\n", + "Write a function that takes a list `radii` as input and returns a list of the corresponding circle areas. Try to set it up from scratch and test it (note that the build-in `map()` function does the same).\n", + "\n", + "You can use the function from the previous exercise if you want." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exercise 3\n", + "Work with a partner to adapt the Mannings equation above to work with conduits (water flowing in pipes), where you input the depth, diameter, slope, and mannings friction coefficient. Hint, you will need the following formulas:\n", + "\n", + "* The central angle ($\\theta$) represents the angle formed by the water surface at the center of the pipe. It must be in radians for use in the area formula:\n", + "\n", + "$$\\theta =2\\arccos \\left(\\frac{r-y}{r}\\right)$$\n", + "\n", + "where r is the radius of the conduit (D/2), y is the depth of watear.\n", + "\n", + "* Calculate the flow area:\n", + "\n", + "$$A = \\frac{r^2(\\theta - \\sin\\theta)}{2}$$\n", + "\n", + "for a less than half-full pipe.\n", + "\n", + "$$A=\\pi r^{2}-\\frac{r^{2}(\\theta _{dry}-\\sin \\theta _{dry})}{2}$$\n", + "\n", + "for a pipe flowing greater than half full.\n", + "\n", + "And the wetted perimeter is:\n", + "\n", + "$$P = r \\cdot \\theta$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "hide_input": false, + "kernelspec": { + "display_name": "Python 3.10 (p310env)", + "language": "python", + "name": "p310env" + }, + "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.10.19" + }, + "latex_envs": { + "LaTeX_envs_menu_present": true, + "autoclose": false, + "autocomplete": true, + "bibliofile": "biblio.bib", + "cite_by": "apalike", + "current_citInitial": 1, + "eqLabelWithNumbers": true, + "eqNumInitial": 1, + "hotkeys": { + "equation": "Ctrl-E", + "itemize": "Ctrl-I" + }, + "labels_anchors": false, + "latex_user_defs": false, + "report_style_numbering": false, + "user_envs_cfg": false + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "391.997px" + }, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Intro2Python/Module6-Functions.ipynb b/Intro2Python/Module6-Functions.ipynb index e973c85..080767e 100644 --- a/Intro2Python/Module6-Functions.ipynb +++ b/Intro2Python/Module6-Functions.ipynb @@ -184,20 +184,20 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Flow rate Q: 43.86 cfs\n" + "Flow rate Q: 20359.95 cfs\n" ] } ], "source": [ - "width = 10 #channel width in ft\n", - "depth = 1 #channel depth in ft\n", + "width = 100 #channel width in ft\n", + "depth = 10 #channel depth in ft\n", "slope = 0.01 #channel slope in ft/ft\n", "\n", "Q = mannings_equation_rect(width, depth, slope) #call mannings_equation_rect function with width, depth, slope, and default n value\n", @@ -501,9 +501,9 @@ "metadata": { "hide_input": false, "kernelspec": { - "display_name": "p310env", + "display_name": "Python 3.10 (p310env)", "language": "python", - "name": "python3" + "name": "p310env" }, "language_info": { "codemirror_mode": {