diff --git a/ch03-first-python-program/hello_world.py b/ch03-first-python-program/hello_world.py new file mode 100644 index 0000000..7ac0be0 --- /dev/null +++ b/ch03-first-python-program/hello_world.py @@ -0,0 +1,6 @@ +# This is a block comment +greeting = "Hello, World" # this is an inline comment +greeting + +# Multiline may help a +# comment for clarity diff --git a/ch04-strings-and-string-methods/string-and-numbers.py b/ch04-strings-and-string-methods/string-and-numbers.py new file mode 100644 index 0000000..7b62a23 --- /dev/null +++ b/ch04-strings-and-string-methods/string-and-numbers.py @@ -0,0 +1,74 @@ +# convert input (string) to numer + +num = input("Enter a number to be doubled: ") +doubled_num = num * 2 +print(doubled_num) + + + +num = input("Enter a number to be doubled: ") +doubled_num = int(num) * 2 +print(doubled_num) + + +# Review exercises + +num_string = "5" +num_int = int(num_string) +print("String to int and multiplied is " + num_string) +print(num_int *2) + + +num_float = float(num_string) +print("Float from string multiplied by 3.5") +print(num_float * 3.5) + + +# string and integer object in print statment + +text = "Hello" +num = 42 +print(text + " " + str(num)) + +# 2 inputs are calculated and written + +print("Please enter two numbers to multiply") +prompt = "Number 1: " +input1 = input(prompt) +prompt = "Number 2: " +input2 = input(prompt) +result = float(input1) * float(input2) +print(result) +print("The product of " + input1 + " and " + input2 + " is " + str(result) + ".") + +# streamline your prints + +name = "Zaphod" +heads = 2 +arms = 3 + +# starting from python 3.6 +print(name + " has " + str(heads) + " heads and " + str(arms) + " arms.") + +# earlier versions use .format() +print("{} has {} heads and {} arms.".format(name, heads, arms)) + + +# formatted strings +print(f"{name} has {heads} heads and {arms} arms.") + +n = 3 +m = 4 +print(f"{n} times {m} is {n*m}") + + +# Review exercise + +weight = 0.2 +animal = "newt" + +print( str(weight) + " kg is the weight of the " + animal) + +print("{} kg is the weight of the {}".format(weight, animal)) + +print(f"{weight} kg is the weight of the {animal}") diff --git a/ch04-strings-and-string-methods/string-challenge-pick-apart.py b/ch04-strings-and-string-methods/string-challenge-pick-apart.py new file mode 100644 index 0000000..2254865 --- /dev/null +++ b/ch04-strings-and-string-methods/string-challenge-pick-apart.py @@ -0,0 +1,14 @@ +'''4.5. Challenge: Pick Apart Your User’s Input +4.5 Challenge: Pick Apart Your User’s +Input +Write a program named first_letter.py that prompts the user for in- +put with the string "Tell me your password:". The program should then +determine the first letter of the user’s input, convert that letter to up- +percase, and display it back. +For example, if the user input is "no", then the program should display +the following output +The first letter you entered was: N''' + +prompt = "Tell me your password: " +user_input = input(prompt) +print("The first letter you entered was: " + user_input[:1].upper()) diff --git a/ch04-strings-and-string-methods/string-concatenation-indexint-slicing.py b/ch04-strings-and-string-methods/string-concatenation-indexint-slicing.py new file mode 100644 index 0000000..f69101a --- /dev/null +++ b/ch04-strings-and-string-methods/string-concatenation-indexint-slicing.py @@ -0,0 +1,48 @@ +# Concatenation +string1 = "abra" +string2 = "cadabra" +magic_string = string1 + string2 +print(magic_string) + +first_name = "Arthur" +last_name = "Dent" +full_name = first_name + " " + last_name +print(full_name) + +# Indexing +flavor = "fig pie" +print("Get character at index 1 of " + flavor ) +print(flavor[1]) + +# get last character +print("Get last charakter") +print(flavor[-1]) + +# substring +flavor_substring = flavor[0:3] +print("Substring 0:3 of flavor") +print(flavor_substring) + +# substring from 3 till end +flavor_end = flavor[3:] +print(flavor_end) + +# no IndexError if I try to slice between boundaries outside the beginning or +# ending of a string +print("End of substring is outside the index range") +print(flavor[:14]) + +print("Start and End are outside the strings lenght") +print(flavor[13:15]) + +# strings are immutable meaning characters cannot be changed +# changes require new string assignments +word = "goal" +print("Initial word " + word) +word = "f" + word[1:] +print("Result after concatenation of f plus word[1:]") +print(word) + +# exercise +test = "bazinga" +print(test[2:6]) diff --git a/ch04-strings-and-string-methods/string-find.py b/ch04-strings-and-string-methods/string-find.py new file mode 100644 index 0000000..ae66b65 --- /dev/null +++ b/ch04-strings-and-string-methods/string-find.py @@ -0,0 +1,56 @@ +# use .find() which returns the index of the start of the substring + +phrase = "the surprise is in here somewhere" +to_find = "surprise" +print("Looking for " + to_find) +print(phrase.find("surprise")) +to_find = "eyjafjallajökull" + +# find() returns -1 if not found +print("Now looking for " + to_find) +print(phrase.find("eyjafjallajökull")) + +# find() is casesensitve and all characters must match +print(phrase.find("SURPRISE")) + +# find() returns only the start indext of the first occurance +msg = "I put a string in your string" +print(msg) +print(msg.find("string")) + +# numbers in string +text = "My number is 555-555-5555" +print(text) +# will cause TypeError +# print("Find 5") +#print(text.find(5)) +print("Find '5'") +print(text.find("5")) + + +# replace +my_story = "I'm telling you the truth; nothing but the truth!" +print("Original: " + my_story) +print("replaced: " + my_story.replace("the truth", "lies")) +print("Call variable again to see it unaltered: " + my_story) +my_story = my_story.replace("the truth", "lies") +print("Finally: " + my_story) + +# to replace various words +sample = "some of the stuff" +print("Go from: " + sample) +new_sample = sample.replace("some of", "all") +new_sample = new_sample.replace("stuff", "things") +print("To: " + new_sample) + +# Review exercises +print("AAA".find("a")) + +exercise2 = "Somebody said something to Samantha." +result2 = exercise2.replace("s", "x") +print(result2) + +exercise3 = "Please give me a word: " +input_from_user = input(exercise3) +print(input_from_user.find("b")) + diff --git a/ch04-strings-and-string-methods/string-interact-with-user.py b/ch04-strings-and-string-methods/string-interact-with-user.py new file mode 100644 index 0000000..5633a8c --- /dev/null +++ b/ch04-strings-and-string-methods/string-interact-with-user.py @@ -0,0 +1,28 @@ +# get input + +input() + +prompt = "Hey, what's up? " +user_input = input(prompt) +print("You said: " + user_input) + + +# do something with the user input + +response = input("What should I shout? ") +shouted_response = response.upper() +print("Well, if you insist..." + shouted_response) + + +# exercise +question = "What is your favourite colour? " +answer = input(question) +print(answer) + +answer_lower = input(question).lower() +print(answer_lower) + +print("Number of characters in your favorite colour is: ") +print(len(answer_lower)) + + diff --git a/ch04-strings-and-string-methods/string-manipulate-with-methods.py b/ch04-strings-and-string-methods/string-manipulate-with-methods.py new file mode 100644 index 0000000..a45c6e2 --- /dev/null +++ b/ch04-strings-and-string-methods/string-manipulate-with-methods.py @@ -0,0 +1,133 @@ +# converting string case + +name1 = "Jean-Luc Picard".lower() +print(name1) + +name2 = "Jean-Luc Picard" +print(name2.lower()) + +print(name1.upper()) + +print("Length of the variable ") +print(len(name1)) + +''' +Remove whitespace three string methods +.rstrip() +.lstrip() +.strip() +''' + +name1 = """Jean-Luc Picard """ +print("Input with whitespace") +print(name1) +print(len(name1)) + +print("\nInput without whitespace") +print(name1.rstrip()) +print(len(name1.rstrip())) + + + + +name1 = """ Jean-Luc Picard""" +print("Input with whitespace") +print(name1) +print(len(name1)) + +print("\nInput without whitespace") +print(name1.lstrip()) +print(len(name1.lstrip())) + + +name1 = """ Jean-Luc Picard """ +print("Input with whitespace") +print(name1) +print(len(name1)) + +print("\nInput without whitespace") +print(name1.strip()) +print(len(name1.strip())) + +''' +.startswith() +.endswith() +''' +print("\nstartswith and endswith") +starship = "Enterprise" +print("Does starship '" + starship + "' start with 'en'?") +print(starship.startswith("en")) + +print("Does starship '" + starship + "' start with 'En'?") +print(starship.startswith("En")) + +print("Does starship '" + starship + "' end with 'risE'?") +print(starship.endswith("risE")) + + +print("""\nUpper and lower do not change the string. + The return a copy""") + + +name = "Picard" +print(name.upper()) +print(name) + +print("To keep the change you need to assign it to the variable") +name = name.upper() +print("Result after name = name.upper()") +print(name) + + + +# exercise + +print("Animal".lower()) +print("Badger".lower()) +bee = "Honey Bee" +print(bee.lower()) +print("Honey Badger".lower()) + +animal = "Animal" +badger = "Badger" +bee = "Honey Bee" +honey_badger = "Honey Badger" +print(animal.upper()) +print(badger.upper()) +print(bee.upper()) +print(honey_badger.upper()) + + +# exercise remove whitespace + +string1 = " Filet Mignon" +string2 = "Brisket " +string3 = " Cheeseburger " + +string1 = string1.lstrip() +string2 = string2.rstrip() +string3 = string3.strip() + +print(string1) +print(string2) +print(string3) + +startwith_string1 = "Becomes" +startwith_string2 = "becomes" +startwith_string3 = "BEAR" +startwith_string4 = " bEautiful" + +print(startwith_string1.startswith("be")) +print(startwith_string2.startswith("be")) +print(startwith_string3.startswith("be")) +print(startwith_string4.startswith("be")) + +startwith_string1 = startwith_string1.lower() +startwith_string3 = startwith_string3.lower() +startwith_string4 = startwith_string4.lstrip().lower() + +print(startwith_string1.startswith("be")) +print(startwith_string2.startswith("be")) +print(startwith_string3.startswith("be")) +print(startwith_string4.startswith("be")) + diff --git a/ch04-strings-and-string-methods/string_stuff.py b/ch04-strings-and-string-methods/string_stuff.py new file mode 100644 index 0000000..7db65ad --- /dev/null +++ b/ch04-strings-and-string-methods/string_stuff.py @@ -0,0 +1,31 @@ +string1 = 'Hello, World' +string2 = "1234" +string3 = "We're #1" +string4 = 'I said, "Put it over by the llama."' +text = "She said, \"What time is it?\"" +long_string = "This multiline string is \ +displayed on one line" +print(long_string) + +paragraph = "This planet has—or rather had—a problem, which was \ +this: most of the people living on it were unhappy for pretty much \ +of the time. Many solutions were suggested for this problem, but \ +most of these were largely concerned with the movements of small \ +green pieces of paper, which is odd because on the whole it wasn't \ +the small green pieces of paper that were unhappy." +print("\nLong paragraph one quote at begin and end\n") +print(paragraph) + +# Triple quoted string preserve whitespace, including newlines +paragraph = """This planet has—or rather had—a problem, which was +this: most of the people living on it were unhappy for pretty much +of the time. Many solutions were suggested for this problem, but +most of these were largely concerned with the movements of small +green pieces of paper, which is odd because on the whole it wasn't +the small green pieces of paper that were unhappy.""" +print("\nNew string called paragraph") +print(paragraph) + +print("""An example of a +... string that spans across multiple lines +... and also preseves whitespace.""") diff --git a/ch04-strings-and-string-methods/translate.py b/ch04-strings-and-string-methods/translate.py new file mode 100644 index 0000000..7ae7da3 --- /dev/null +++ b/ch04-strings-and-string-methods/translate.py @@ -0,0 +1,13 @@ +# get input +user_input = input("Enter some text: ") + +edited_version = user_input.replace("a", "4") +edited_version = edited_version.replace("b", "8") +edited_version = edited_version.replace("e", "3") +edited_version = edited_version.replace("l", "1") +edited_version = edited_version.replace("o", "0") +edited_version = edited_version.replace("s", "5") +edited_version = edited_version.replace("t", "7") + +print(edited_version) + diff --git a/ch05-numbers-in-python/arithmetic-operators-and-expressions.py b/ch05-numbers-in-python/arithmetic-operators-and-expressions.py new file mode 100644 index 0000000..e42f9a1 --- /dev/null +++ b/ch05-numbers-in-python/arithmetic-operators-and-expressions.py @@ -0,0 +1,11 @@ +# challenge + +prompt1 = "Enter a base: " +prompt2 = "Enter an exponent: " + +base = input(prompt1) +exponent = input(prompt2) + +print(f"{base} to the power of {exponent} = {float(base)**float(exponent)}") + + diff --git a/ch05-numbers-in-python/integers-and-floats.py b/ch05-numbers-in-python/integers-and-floats.py new file mode 100644 index 0000000..a3dcfa4 --- /dev/null +++ b/ch05-numbers-in-python/integers-and-floats.py @@ -0,0 +1,59 @@ +separator = "#" +separator_multiplier = 50 + +# integers +print(type(1)) + +# literal integers are type in +num = 23 + +# integers converted from strings are not called literal integers +text = "34" +num2 = int(text) +print(num2) + +num1 = 1000000 +# you can use underscores to group large integer to make them easier to read +num2 = 1_000_000 + +print(num1 - num2) + +# integers do not have a limitation in phython +print(separator * separator_multiplier) + +# floating point numbers +print(type(2.5)) + +print(float("2.33")) + +# different ways of representing floating point numbers +a = 1000000.0 +b = 1_000_000.0 +# exponential notation +# number multiplied by 10 raised to the power of number after e +# 1 e 6 = 1 * 10^6 +c = 1e6 + +print("Input: 1000000.0") +print(str(a)) +print("Input: 1_000_000.0") +print(str(b)) +print("Input: 1e6") +print(str(c)) + +# When you reach the maximum floating-point number, Python returns +# a special float value, inf == infinity + + +# Review exercises + +num1 = 25_000_000.0 +num2 = 25e6 +print(num1) +print(num2) + +num = 175e3 +print(num) + +# border to inf +print(2e308) diff --git a/ch05-numbers-in-python/math-functions-and-numbers-methods.py b/ch05-numbers-in-python/math-functions-and-numbers-methods.py new file mode 100644 index 0000000..ed03edd --- /dev/null +++ b/ch05-numbers-in-python/math-functions-and-numbers-methods.py @@ -0,0 +1,52 @@ +print(round(2.3)) + +print(round(2.7)) + + +print(round(2.5)) +print(round(3.5)) +print(round(4.5)) + +# round with positions after the comma +print(round(2.74653, 3)) + + +# skip abs() for absolute ValueError + +# skip pow which is like ** + +# review exercises + +''' +Write a program that asks the user to input a number and then +displays that number rounded to two decimal places. When run, +your program should look like this: +''' + +prompt = "Enter a number: " +user_input = input(prompt) +print(f"{user_input} rounded to 2 decimal places is {round(float(user_input), 2)}") + +''' +Write a program that asks the user to input a number and then +displays the absolute value of that number. When run, your +program should look like this: +''' + +user_input = input(prompt) +print("The absolute value of " + user_input + " is " + str(abs(float(user_input)))) + +''' +Write a program that asks the user to input two numbers by using +input() twice, then displays whether the difference between those +two numbers is an integer. When run, your program should look +like this: +''' + +prompt1 = "Enter a number: " +prompt2 = "Enter another number: " + +user_input1 = input(prompt1) +user_input2 = input(prompt2) + +print("The difference between {} and {} is an integer? {}".format(user_input1, user_input2, (float(user_input1) - float(user_input2)).is_integer())) diff --git a/ch05-numbers-in-python/print-numbers-in-style.py b/ch05-numbers-in-python/print-numbers-in-style.py new file mode 100644 index 0000000..2518030 --- /dev/null +++ b/ch05-numbers-in-python/print-numbers-in-style.py @@ -0,0 +1,58 @@ +n = 7.125 +print(n) +print(f"The value of n is {n}") +print(f"The value of n is {n:.2f}") + +n = 7.126 +print(n) +print(f"The value of n is {n}") +print(f"The value of n is {n:.2f}") + +print(n) +print(f"The value of n is {n}") +print(f"The value of n is {n:.1f}") + +# add commas to numbers to make them more readable to users +# points or space does not work + +n = 123456789 +print(f"The value of n is {n:,}") + +# rount and format number +n = 1234.56 +print(f"The value of n is {n:,.2f}") + +# ,.2f is useful for displaying currency values +balance = 2000.0 +spent = 256.35 +remaining = balance - spent +print(f"After spending ${spent:,.2f}, I was left with ${remaining:,.2f}") + +# Percent % option +ratio = 0.9 +print(f"Over {ratio:.1%} of Pythonistas say 'Real Python rocks!'") + +# Display percentage with 2 decimal places +print(f"Over {ratio:.2%} of Pythonistas say 'Real Python rocks!'") + +''' +1. Print the result of the calculation 3 ** .125 as a fixed-point number +with three decimal places. +''' +result = 3 ** .125 +print(f"The result is {result:.3f}") + +''' +2. Print the number 150000 as currency with the thousands grouped +with commas. Currency should be displayed with two decimal +places. +''' +currency = 150000 +print(f"{currency:,.2f}") + +''' +3. Print the result of 2 / 10 as a percentage with no decimal places. +The output should look like 20%. +''' +percentage = 2 / 10 +print(f"{percentage:.0%}") diff --git a/ch06-functions-and-loops/invest.py b/ch06-functions-and-loops/invest.py new file mode 100644 index 0000000..618a767 --- /dev/null +++ b/ch06-functions-and-loops/invest.py @@ -0,0 +1,12 @@ +def invest(amount, rate, years): + '''Display year on year growth of an initial investment''' + for y in range(1, years + 1): + amount = amount * (1 + rate) + print(f"year {y}: ${amount:,.2f}") + +x = float(input("Please enter an initial amount: ")) +y = float(input("Please enter a rage: ")) +z = int(input("Please enter a number of years: ")) + +invest(x, y, z) + diff --git a/ch06-functions-and-loops/run-in-circles.py b/ch06-functions-and-loops/run-in-circles.py new file mode 100644 index 0000000..b9db544 --- /dev/null +++ b/ch06-functions-and-loops/run-in-circles.py @@ -0,0 +1,92 @@ +# while loop +# perfect for repeating a section of code while some +# condition is met + +num = float(input("Enter a positive number: ")) + +while(num <= 0): + print("That's not a positive number!") + num = float(input("Enter a positive number: ")) + +print("You did it!") + +# for loop +# for repeating a section of code a specific number of times +# executes a section of code once for eacht item in a collection? +# sounds like a foreach in C# + +for letter in "Python": + print(letter) + +print("\n") + +# same as while loop +word = "Python" +index = 0 + +while index < len(word): + print(word[index]) + index = index + 1 + +for n in range(3): + print(n) + print("Python") + +# range can have a start and an end point, whereas the start is included +# while end is not +print("\nfor loop with a range of 10 to 20") +for n in range(10, 20): + print(n * n) + +# example to split an amount between a raising number of people +# 2, 3, 4 and 5 +amount = float(input("Enter an amount: ")) + +for num_people in range(2, 6): + print(f"{num_people} people: ${amount / num_people:,.2f} each") + +# nested loops - loop inside a loop +print("\nNested loop sample:") +for n in range(1, 4): + for j in range(4, 7): + print(f"n = {n} and j = {j}") + + +# review exercise: + +''' +1. Write a for loop that prints out the integers 2 through 10, each on +a new line, using range(). +''' +for n in range(2, 11): + print(n) + +''' +2. Write a while loop that prints out the integers 2 through 10. (Hint: +You’ll need to create a new integer first.) +''' +count = 2 + +while count <= 10: + print(count) + count += 1 + + +''' +3. Write a function called doubles() that takes a number as its input +and doubles it. Then use doubles() in a loop to double the number 2 +three times, displaying each result on a separate line. Here’s some +sample output: +4 +8 +16 +''' +def doubles(x): + '''Takes a number and doubles it''' + return x * 2 + +current_value = 2 + +for n in range(3): + current_value = doubles(current_value) + print(current_value) diff --git a/ch06-functions-and-loops/write-own-funktions.py b/ch06-functions-and-loops/write-own-funktions.py new file mode 100644 index 0000000..5c4a8a9 --- /dev/null +++ b/ch06-functions-and-loops/write-own-funktions.py @@ -0,0 +1,94 @@ +def multiply(x, y): # function signature + # function body + '''Return the product of two numbers x and y.''' + product = x * y + return product + print("Will never be reached, because of return before") + +print("Outside the function") +print("Call multiply with the arguments of 2 and 3") +print(multiply(2, 3)) + +print(multiply("Hello ", 2)) + + +def greet(name): + print(f"Hello, {name}!") + +my_value = greet("Sam") +print(my_value) +print(type(my_value)) + +# review exercises +'''1. Write a function called cube() that takes one number parameter +and returns the value of that number raised to the third power. +Test the function by calling your cube() function on a few different +numbers and displaying the results. +''' +def cube(x): + '''Return the number provided x raised to the third power''' + result = pow(x, 3) + print(f"Result of cube({str(x)}) is {result}") + return result + +cube(2) +cube(3) +cube(99) +cube(-1.2) + + +''' +2. Write a function called greet() that takes one string parameter +called name and displays the text "Hello !", where is +replaced by the value of the name parameter. +''' + +def greet(name): + '''Display the text "Hello !" where name is string given''' + print(f"Hello {name}!") + +greet("Sam") +greet("Willie") +greet("Everyone") + + +# Challenges + +''' +1. convert_cel_to_far(), which takes one float parameter representing degrees +Celsius and returns a float representing the same temperature in degrees +Fahrenheit using the following formula: +F = C * 9/5 + 32 +''' +def convert_cel_to_far(c): + '''Take float parameter c representing degrees Celsius and return a +float representing the same temperature in degrees Fahrenheit''' + far = c * 9/5 + 32 + return far + +''' +2. convert_far_to_cel(), which takes one float parameter representing degrees Fahrenheit and returns a float representing the same +temperature in degrees Celsius using the following formula: +C = (F - 32) * 5/9 +''' + +def convert_far_to_cel(f): + '''Take float parameter f representing degrees Fahrenheit and return a +a float representing the same temperature in degrees Celsius''' + cel = (f - 32) * 5/9 + return cel + +prompt_far = "Enter a temperature in degrees F: " +prompt_cel = "Enter a temperature in degrees C: " + +far = input(prompt_far) +result_cel = convert_far_to_cel(float(far)) +print(f"{far} degrees F = {result_cel:.2f} degrees C") + +cel = input(prompt_cel) +result_far = convert_cel_to_far(float(cel)) +print(f"{cel} degrees C = {result_far:.2f} degrees F") + + + + diff --git a/ch07-fiding-and-fixing-code-bugs/learn-debug-with-idle.py b/ch07-fiding-and-fixing-code-bugs/learn-debug-with-idle.py new file mode 100644 index 0000000..3424883 --- /dev/null +++ b/ch07-fiding-and-fixing-code-bugs/learn-debug-with-idle.py @@ -0,0 +1,16 @@ +for i in range(1,4): + j = i * 2 + print(f"i is {i} and j is {j}") + +# Buggy code +def add_underscores(word): + new_word = "_" + # using letter instead of i is considered more pythonic + for letter in word: + new_word = new_word + letter + "_" + #print(f"i = {i}; new_word = {new_word}") + return new_word + +phrase = "hello" +print("Call add_underscores(phrase) results in: ") +print(add_underscores(phrase)) diff --git a/ch08-conditional-logic/.ipynb_checkpoints/8a-challenge-simulate-a-coin-toss-experiment-checkpoint.py b/ch08-conditional-logic/.ipynb_checkpoints/8a-challenge-simulate-a-coin-toss-experiment-checkpoint.py new file mode 100644 index 0000000..04a3cb5 --- /dev/null +++ b/ch08-conditional-logic/.ipynb_checkpoints/8a-challenge-simulate-a-coin-toss-experiment-checkpoint.py @@ -0,0 +1,55 @@ +# 8.8 - Challenge: Simulate a Coin Toss Experiment +# Solution to challenge + + +# Simulate the results of a series of coin tosses and track the results + +# This one is tricky to structure correctly. Try writing out the logic before +# you start coding. Some additional pointers if you're stuck: +# 1. You will need to use a `for` loop over a range of trials. +# 2. For each trial, first you should check the outcome of the first flip. +# 3. Make sure you add the first flip to the total number of flips. +# 4. After the first toss, you'll need another loop to keep flipping while you +# get the same result as the first flip. + +import random + + +def coin_flip(): + """Randomly return 'heads' or 'tails'.""" + if random.randint(0, 1) == 0: + return "heads" + else: + return "tails" + + +flips = 0 +num_trials = 10_000 + +for trial in range(num_trials): + if coin_flip() == "heads": + # Increment the number of flips by 1 + flips = flips + 1 + while coin_flip() == "heads": + # Keep incrementing the total number of flips + # until "tails" is returned by coin_flip() + flips = flips + 1 + # Once coin_flip() return "tails", the loop will exit, + # but we need to add one more to flips to track the + # last flip that generated "tails" + flips = flips + 1 + else: + # coin_flip() returned "tails" on the first flip. + # Increment the number of flips by 1 + flips = flips + 1 + while coin_flip() == "tails": + # Keep incrementing the total number of flips + # until "heads" is returned by coin_flip() + flips = flips + 1 + # Once coin_flip() returns "heads", the loop will exit, + # but we need to add one more to flips to track the + # last flip that generated "heads" + flips = flips + 1 + +avg_flips_per_trial = flips / num_trials +print(f"The average number of flips per trial is {avg_flips_per_trial}.") diff --git a/ch08-conditional-logic/.ipynb_checkpoints/8b-challenge-simulate-a-coin-toss-experiment-checkpoint.py b/ch08-conditional-logic/.ipynb_checkpoints/8b-challenge-simulate-a-coin-toss-experiment-checkpoint.py new file mode 100644 index 0000000..9f3effe --- /dev/null +++ b/ch08-conditional-logic/.ipynb_checkpoints/8b-challenge-simulate-a-coin-toss-experiment-checkpoint.py @@ -0,0 +1,42 @@ +# 8.8 - Challenge: Simulate a Coin Toss Experiement +# Alternative solution to challenge + + +# Simulate the results of a series of coin tosses and track the results + +# This one is tricky to structure correctly. Try writing out the logic before +# you start coding. Some additional pointers if you're stuck: +# 1. You will need to use a `for` loop over a range of trials. +# 2. For each trial, first you should check the outcome of the first flip. +# 3. Make sure you add the first flip to the total number of flips. +# 4. After the first toss, you'll need another loop to keep flipping while you +# get the same result as the first flip. + +import random + + +def coin_flip(): + """Randomly return 'heads' or 'tails'.""" + if random.randint(0, 1) == 0: + return "heads" + else: + return "tails" + + +flips = 0 +num_trials = 10_000 + +for trial in range(num_trials): + # Flip the coin once and increment the flips tally by 1 + first_flip = coin_flip() + flips = flips + 1 + # Continue flipping the coin and updating the tally until + # a different result is returned by coin_flip() + while coin_flip() == first_flip: + flips = flips + 1 + # Increment the flip tally once more to account for the + # final flip with a different result + flips = flips + 1 + +avg_flips_per_trial = flips / num_trials +print(f"The average number of flips per trial is {avg_flips_per_trial}.") diff --git a/ch08-conditional-logic/.ipynb_checkpoints/8c-challenge-simulate-a-coin-toss-experiment-checkpoint.py b/ch08-conditional-logic/.ipynb_checkpoints/8c-challenge-simulate-a-coin-toss-experiment-checkpoint.py new file mode 100644 index 0000000..753e91d --- /dev/null +++ b/ch08-conditional-logic/.ipynb_checkpoints/8c-challenge-simulate-a-coin-toss-experiment-checkpoint.py @@ -0,0 +1,49 @@ +# 8.8 - Challenge: Simulate a Coin Toss Experiement +# Alternative solution to challenge using functions + + +# Simulate the results of a series of coin tosses and track the results + +# This one is tricky to structure correctly. Try writing out the logic before +# you start coding. Some additional pointers if you're stuck: +# 1. You will need to use a `for` loop over a range of trials. +# 2. For each trial, first you should check the outcome of the first flip. +# 3. Make sure you add the first flip to the total number of flips. +# 4. After the first toss, you'll need another loop to keep flipping while you +# get the same result as the first flip. + +import random + + +def single_trial(): + """Simulate repeatedly flipping a coin until both heads and tails are seen.""" + # This function uses random.randint() to simulate a single coin toss. + # randint(0, 1) randomly returns 0 or 1 with equal probability. We can + # use 0 to represent heads and 1 to represent tails. + + # Flip the coin the first time + flip_result = random.randint(0, 1) + # Keep a tally of how many times the coin has been flipped. We've only + # flipped once so the initial count is 1. + flip_count = 1 + + # Continue to flip the coin until randint(0, 1) returns something + # different than the original flip_result + while flip_result == random.randint(0, 1): + flip_count = flip_count + 1 + + # The last step in the loop flipped the coin but didn't update the tally, + # so we need to increase the flip_count by 1 + flip_count = flip_count + 1 + return flip_count + + +def flip_trial_avg(num_trials): + """Calculate the average number of flips per trial over num_trials total trials.""" + total = 0 + for trial in range(num_trials): + total = total + single_trial() + return total / num_trials + + +print(f"The average number of coin flips was {flip_trial_avg(10_000)}") diff --git a/ch08-conditional-logic/.ipynb_checkpoints/Chapter08-checkpoint.ipynb b/ch08-conditional-logic/.ipynb_checkpoints/Chapter08-checkpoint.ipynb new file mode 100644 index 0000000..cc72915 --- /dev/null +++ b/ch08-conditional-logic/.ipynb_checkpoints/Chapter08-checkpoint.ipynb @@ -0,0 +1,328 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "51ae75fb-8d67-4f36-928d-683f0aee1916", + "metadata": {}, + "outputs": [], + "source": [ + "Chapter 08 exercises" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "21d7275c-634f-49a2-838d-2bd8175156c1", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The ratio is 0.9972039145196725\n" + ] + } + ], + "source": [ + "# %load fair-coin.py\n", + "import random\n", + "\n", + "def toss():\n", + " \"\"\" Randomly returns 'heads' or 'tails' \"\"\"\n", + " if random.randint(0,1) == 0:\n", + " return 'heads'\n", + " else:\n", + " return 'tails'\n", + "\n", + "heads_tally = 0\n", + "tails_tally = 0\n", + "\n", + "for trial in range(10_000):\n", + " # Keep track of the heads and tails count separatly for whatever reason i thought i might need this\n", + " if toss() == 'heads':\n", + " heads_tally = heads_tally + 1\n", + " else:\n", + " tails_tally = tails_tally + 1\n", + "\n", + "# Calculate the ratio\n", + "ratio = heads_tally / tails_tally\n", + "print(f\"The ratio is {ratio}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1e54adfa-5d0f-4fa9-b833-7330340863a1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The ration of heads to tail is 1.0\n" + ] + } + ], + "source": [ + "# %load unfair-coin.py\n", + "import random\n", + "\n", + "def unfair_toss(probability_of_tails):\n", + " if random.random() < probability_of_tails:\n", + " return 'tails'\n", + " else:\n", + " return 'heads'\n", + "\n", + "\n", + "heads_tally = 0\n", + "tails_tally = 0\n", + "\n", + "for trial in range(10_000):\n", + " if unfair_toss(0.8) == 'heads':\n", + " heads_tally =+ 1\n", + " else:\n", + " tails_tally =+ 1\n", + " \n", + "ratio = heads_tally / tails_tally\n", + "print(f\"The ration of heads to tail is {ratio}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "a9004e5e-d219-4fb2-b4a1-94f7fdfa2377", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The ration of heads to tail is 0.2484394506866417\n" + ] + } + ], + "source": [ + "# %load unfair-coin.py\n", + "import random\n", + "\n", + "def unfair_toss(probability_of_tails):\n", + " if random.random() < probability_of_tails:\n", + " return 'tails'\n", + " else:\n", + " return 'heads'\n", + "\n", + "\n", + "heads_tally = 0\n", + "tails_tally = 0\n", + "\n", + "for trial in range(10_000):\n", + " if unfair_toss(0.8) == 'heads':\n", + " heads_tally += 1\n", + " else:\n", + " tails_tally += 1\n", + " \n", + "ratio = heads_tally / tails_tally\n", + "print(f\"The ration of heads to tail is {ratio}\")" + ] + }, + { + "cell_type": "markdown", + "id": "645347ab-a76d-4d2c-a1f5-531afae4bf50", + "metadata": {}, + "source": [ + "## Review exercise:\n", + "\n", + "1. Write a function called roll() that uses randint() to simulate rolling\n", + "a fair die by returning a random integer between 1 and 6.\n", + "2. Write a program that simulates ten thousand rolls of a fair die and\n", + "displays the average number rolled." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "9bca0f33-bb5a-476e-b71f-f7174b75f18b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "The average rolled is 3.0142\n" + ] + } + ], + "source": [ + "import random\n", + "\n", + "def roll():\n", + " return random.randint(0,6)\n", + "\n", + "print(roll())\n", + "\n", + "sum = 0\n", + "\n", + "for trail in range(10_000):\n", + " sum += roll()\n", + "\n", + "average_roll = sum / 10_000\n", + "\n", + "print(f\"The average rolled is {average_roll}\")\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "96dc44a9-1452-4c6e-8906-07f75f1d8af7", + "metadata": {}, + "source": [ + "# Challenge: Simulate a Coin Toss Experiment\n", + "Suppose you flip a fair coin repeatedly until it lands on heads and tails\n", + "at least one time each. In other words, after the first flip, you continue\n", + "to flip the coin until it lands on the other side.\n", + "\n", + "Doing this generates a sequence of heads and tails. For example, the\n", + "first time you do this experiment, the sequence might be heads, heads,\n", + "tails.\n", + "\n", + "On average, how many flips are needed for the sequence to contain\n", + "both heads and tails?\n", + "\n", + "Write a simulation that runs ten thousand trials of the experiment and\n", + "prints the average number of flips per trial." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "9f16a363-a522-4b7f-aaaf-b3f0096bc413", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "On average 2.9899 flips were needed\n" + ] + } + ], + "source": [ + "import random\n", + "\n", + "def coin_toss():\n", + " if random.randint(0,1) == 0:\n", + " \"\"\" Randomly returns 'heads' or 'tails' \"\"\"\n", + " return 'heads'\n", + " else:\n", + " return 'tails'\n", + "\n", + "count = 0\n", + "\n", + "for trial in range(10_000):\n", + " heads_tally = 0\n", + " tails_tally = 0\n", + " #print(f\"Current count: {count}\")\n", + " \n", + " while (heads_tally < 1) or (tails_tally < 1):\n", + " if coin_toss() == 'heads':\n", + " heads_tally += 1\n", + " else:\n", + " tails_tally += 1\n", + " else:\n", + " count += heads_tally + tails_tally\n", + " continue\n", + "\n", + "flips = count / 10_000\n", + "\n", + "print(f\"On average {flips} flips were needed\") " + ] + }, + { + "cell_type": "markdown", + "id": "a59b99dd-fb42-4b61-8d5a-8ef53d3c25c0", + "metadata": {}, + "source": [ + "## Second variante:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "c0b88bda-c1fd-41e3-ba85-7f589b77df13", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "On average 2.9899 flips were needed\n" + ] + } + ], + "source": [ + "import random\n", + "\n", + "def coin_toss():\n", + " if random.randint(0,1) == 0:\n", + " \"\"\" Randomly returns 'heads' or 'tails' \"\"\"\n", + " return 'heads'\n", + " else:\n", + " return 'tails'\n", + "\n", + "flips = 0\n", + "\n", + "for trial in range(10_000):\n", + " # Track first flip result\n", + " first_flip = coin_toss()\n", + " # count flip\n", + " flips += 1\n", + " # continue to count as long as the result equals the first flip\n", + " while coin_toss() == first_flip:\n", + " flips += 1\n", + " continue\n", + " else:\n", + " # break the loop after different result from coint_toss, do not forget to count this flip\n", + " flips += 1\n", + " break\n", + "\n", + "# Calculate the average flips it took to get both sides at least once\n", + "average_flips = count / 10_000\n", + "\n", + "print(f\"On average {average_flips} flips were needed\") " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f0b2d87-00b9-489b-8a91-f968c6192404", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.14.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ch08-conditional-logic/.ipynb_checkpoints/break-out-of-the-pattern-checkpoint.py b/ch08-conditional-logic/.ipynb_checkpoints/break-out-of-the-pattern-checkpoint.py new file mode 100644 index 0000000..723c1fd --- /dev/null +++ b/ch08-conditional-logic/.ipynb_checkpoints/break-out-of-the-pattern-checkpoint.py @@ -0,0 +1,69 @@ + +print("Example using 'break'") +for n in range(4): + if n == 2: + break + print(n) + +print(f"Finished with n = {n}\n") + +print("Example using 'continue'") +for i in range(4): + if i == 2: + continue + print(i) + +print(f"Finished with i = {i}") + +# for ... else loop + +user_phrase = input("Enter a phrase to evaluate: ") + +for character in user_phrase: + if character == "X": + break +else: + print("There was no 'X' in the phrase") + +print("Final statement") + +# practical example for a 'for ... else' loop + +for n in range(3): + password = input("Password: ") + if password == "I<3Bieber": + break + print("Password is incorrect.") +else: + print("Suspicious activity. The authorities have been alerted.") + + +# review exercises + +''' +1. Using break, write a program that repeatedly asks the user for some +input and quits only if the user enters "q" or "Q". +''' + +escape = 'q' +prompt = "Please enter some text: " +user_input = "" + +while True: + user_input = input(prompt).lower() + if user_input == escape: + break + +print("You did escape") + +''' +2. Using continue, write a program that loops over the numbers 1 to +50 and prints all numbers that are not multiples of 3. +''' + +print("\nHere are the number from 1 to 50 except the multiples of 3") + +for num in range(1,51): + if num % 3 == 0: + continue + print(num) diff --git a/ch08-conditional-logic/.ipynb_checkpoints/fair-coin-checkpoint.py b/ch08-conditional-logic/.ipynb_checkpoints/fair-coin-checkpoint.py new file mode 100644 index 0000000..975549f --- /dev/null +++ b/ch08-conditional-logic/.ipynb_checkpoints/fair-coin-checkpoint.py @@ -0,0 +1,19 @@ +import random + +def toss(): + if random.randint(0,1) == 0: + return 'heads' + else: + return 'tails' + +heads_tally = 0 +tails_tally = 0 + +for trial in range(10_000): + if toss == 'heads': + heads_tally = heads_tally + 1 + else: + tails_tally = tails_tally + 1 + +ratio = heads_tally / tails_tally +print(f"The ratio is {ratio}") diff --git a/ch08-conditional-logic/.ipynb_checkpoints/recover-from-errors-checkpoint.py b/ch08-conditional-logic/.ipynb_checkpoints/recover-from-errors-checkpoint.py new file mode 100644 index 0000000..028aa76 --- /dev/null +++ b/ch08-conditional-logic/.ipynb_checkpoints/recover-from-errors-checkpoint.py @@ -0,0 +1,67 @@ +try: + number = int(input("Enter an integer: ")) +except ValueError: + print("That was not an integer") + +print(number) + + +# multiple exception +def divide(num1, num2): + try: + print(num1 / num2) + except (TypeError, ZeroDivisionError): + print("encountered a problem") + + +divide(3, 6) +divide(4, 0) +divide(6, 's') + + +def divide2(num1, num2): + try: + print(num1 / num2) + except TypeError: + print("Both arguments must be numbers") + except ZeroDivisionError: + print("num2 must not be 0") + +divide2(3, 6) +divide2(4, 0) +divide2(6, 's') + +# review exercises + +''' +1. Write a program that repeatedly asks the user to input an integer. +If the user enters something other than an integer, then the +program should catch the ValueError and display the message "Try +again." +Once the user enters an integer, the program should display +the number back to the user and end without crashing. +''' + +keep_running = True + +while(keep_running): + try: + num = int(input("Enter an integer: ")) + except ValueError: + print("Try again") + continue + keep_running = False + +print(num) + + +''' +2. Write a program that asks the user to input a string and an integer +n, then displays the character at index n in the string. +Use error handling to make sure the program doesn’t crash +if the user enters something other than an integer or if the index +is out of bounds. The program should display a different message +depending on which error occurs. +''' + + diff --git a/ch08-conditional-logic/.ipynb_checkpoints/unfair-coin-checkpoint.py b/ch08-conditional-logic/.ipynb_checkpoints/unfair-coin-checkpoint.py new file mode 100644 index 0000000..1379cb4 --- /dev/null +++ b/ch08-conditional-logic/.ipynb_checkpoints/unfair-coin-checkpoint.py @@ -0,0 +1,20 @@ +import random + +def unfair_toss(probability_of_tails): + if random.random() < probability_of_tails: + return 'tails' + else: + return 'heads' + + +heads_tally = 0 +tails_tally = 0 + +for trial in range(10_000): + if unfair_toss(0.8) == 'heads': + heads_tally += 1 + else: + tails_tally += 1 + +ratio = heads_tally / tails_tally +print(f"The ration of heads to tail is {ratio}") \ No newline at end of file diff --git a/ch08-conditional-logic/6-recover-from-errors.py b/ch08-conditional-logic/6-recover-from-errors.py index 250144b..93857f3 100644 --- a/ch08-conditional-logic/6-recover-from-errors.py +++ b/ch08-conditional-logic/6-recover-from-errors.py @@ -12,6 +12,10 @@ break except ValueError: print("try again") + # else: + # print("All went well.") + finally: + print("Done.") # Exercise 2 @@ -26,3 +30,5 @@ print("Invalid number") except IndexError: print("Index is out of bounds") +finally: + print("Hit finally") diff --git a/ch08-conditional-logic/Chapter08.ipynb b/ch08-conditional-logic/Chapter08.ipynb new file mode 100644 index 0000000..cc72915 --- /dev/null +++ b/ch08-conditional-logic/Chapter08.ipynb @@ -0,0 +1,328 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "51ae75fb-8d67-4f36-928d-683f0aee1916", + "metadata": {}, + "outputs": [], + "source": [ + "Chapter 08 exercises" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "21d7275c-634f-49a2-838d-2bd8175156c1", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The ratio is 0.9972039145196725\n" + ] + } + ], + "source": [ + "# %load fair-coin.py\n", + "import random\n", + "\n", + "def toss():\n", + " \"\"\" Randomly returns 'heads' or 'tails' \"\"\"\n", + " if random.randint(0,1) == 0:\n", + " return 'heads'\n", + " else:\n", + " return 'tails'\n", + "\n", + "heads_tally = 0\n", + "tails_tally = 0\n", + "\n", + "for trial in range(10_000):\n", + " # Keep track of the heads and tails count separatly for whatever reason i thought i might need this\n", + " if toss() == 'heads':\n", + " heads_tally = heads_tally + 1\n", + " else:\n", + " tails_tally = tails_tally + 1\n", + "\n", + "# Calculate the ratio\n", + "ratio = heads_tally / tails_tally\n", + "print(f\"The ratio is {ratio}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1e54adfa-5d0f-4fa9-b833-7330340863a1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The ration of heads to tail is 1.0\n" + ] + } + ], + "source": [ + "# %load unfair-coin.py\n", + "import random\n", + "\n", + "def unfair_toss(probability_of_tails):\n", + " if random.random() < probability_of_tails:\n", + " return 'tails'\n", + " else:\n", + " return 'heads'\n", + "\n", + "\n", + "heads_tally = 0\n", + "tails_tally = 0\n", + "\n", + "for trial in range(10_000):\n", + " if unfair_toss(0.8) == 'heads':\n", + " heads_tally =+ 1\n", + " else:\n", + " tails_tally =+ 1\n", + " \n", + "ratio = heads_tally / tails_tally\n", + "print(f\"The ration of heads to tail is {ratio}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "a9004e5e-d219-4fb2-b4a1-94f7fdfa2377", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The ration of heads to tail is 0.2484394506866417\n" + ] + } + ], + "source": [ + "# %load unfair-coin.py\n", + "import random\n", + "\n", + "def unfair_toss(probability_of_tails):\n", + " if random.random() < probability_of_tails:\n", + " return 'tails'\n", + " else:\n", + " return 'heads'\n", + "\n", + "\n", + "heads_tally = 0\n", + "tails_tally = 0\n", + "\n", + "for trial in range(10_000):\n", + " if unfair_toss(0.8) == 'heads':\n", + " heads_tally += 1\n", + " else:\n", + " tails_tally += 1\n", + " \n", + "ratio = heads_tally / tails_tally\n", + "print(f\"The ration of heads to tail is {ratio}\")" + ] + }, + { + "cell_type": "markdown", + "id": "645347ab-a76d-4d2c-a1f5-531afae4bf50", + "metadata": {}, + "source": [ + "## Review exercise:\n", + "\n", + "1. Write a function called roll() that uses randint() to simulate rolling\n", + "a fair die by returning a random integer between 1 and 6.\n", + "2. Write a program that simulates ten thousand rolls of a fair die and\n", + "displays the average number rolled." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "9bca0f33-bb5a-476e-b71f-f7174b75f18b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "The average rolled is 3.0142\n" + ] + } + ], + "source": [ + "import random\n", + "\n", + "def roll():\n", + " return random.randint(0,6)\n", + "\n", + "print(roll())\n", + "\n", + "sum = 0\n", + "\n", + "for trail in range(10_000):\n", + " sum += roll()\n", + "\n", + "average_roll = sum / 10_000\n", + "\n", + "print(f\"The average rolled is {average_roll}\")\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "96dc44a9-1452-4c6e-8906-07f75f1d8af7", + "metadata": {}, + "source": [ + "# Challenge: Simulate a Coin Toss Experiment\n", + "Suppose you flip a fair coin repeatedly until it lands on heads and tails\n", + "at least one time each. In other words, after the first flip, you continue\n", + "to flip the coin until it lands on the other side.\n", + "\n", + "Doing this generates a sequence of heads and tails. For example, the\n", + "first time you do this experiment, the sequence might be heads, heads,\n", + "tails.\n", + "\n", + "On average, how many flips are needed for the sequence to contain\n", + "both heads and tails?\n", + "\n", + "Write a simulation that runs ten thousand trials of the experiment and\n", + "prints the average number of flips per trial." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "9f16a363-a522-4b7f-aaaf-b3f0096bc413", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "On average 2.9899 flips were needed\n" + ] + } + ], + "source": [ + "import random\n", + "\n", + "def coin_toss():\n", + " if random.randint(0,1) == 0:\n", + " \"\"\" Randomly returns 'heads' or 'tails' \"\"\"\n", + " return 'heads'\n", + " else:\n", + " return 'tails'\n", + "\n", + "count = 0\n", + "\n", + "for trial in range(10_000):\n", + " heads_tally = 0\n", + " tails_tally = 0\n", + " #print(f\"Current count: {count}\")\n", + " \n", + " while (heads_tally < 1) or (tails_tally < 1):\n", + " if coin_toss() == 'heads':\n", + " heads_tally += 1\n", + " else:\n", + " tails_tally += 1\n", + " else:\n", + " count += heads_tally + tails_tally\n", + " continue\n", + "\n", + "flips = count / 10_000\n", + "\n", + "print(f\"On average {flips} flips were needed\") " + ] + }, + { + "cell_type": "markdown", + "id": "a59b99dd-fb42-4b61-8d5a-8ef53d3c25c0", + "metadata": {}, + "source": [ + "## Second variante:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "c0b88bda-c1fd-41e3-ba85-7f589b77df13", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "On average 2.9899 flips were needed\n" + ] + } + ], + "source": [ + "import random\n", + "\n", + "def coin_toss():\n", + " if random.randint(0,1) == 0:\n", + " \"\"\" Randomly returns 'heads' or 'tails' \"\"\"\n", + " return 'heads'\n", + " else:\n", + " return 'tails'\n", + "\n", + "flips = 0\n", + "\n", + "for trial in range(10_000):\n", + " # Track first flip result\n", + " first_flip = coin_toss()\n", + " # count flip\n", + " flips += 1\n", + " # continue to count as long as the result equals the first flip\n", + " while coin_toss() == first_flip:\n", + " flips += 1\n", + " continue\n", + " else:\n", + " # break the loop after different result from coint_toss, do not forget to count this flip\n", + " flips += 1\n", + " break\n", + "\n", + "# Calculate the average flips it took to get both sides at least once\n", + "average_flips = count / 10_000\n", + "\n", + "print(f\"On average {average_flips} flips were needed\") " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f0b2d87-00b9-489b-8a91-f968c6192404", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.14.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ch08-conditional-logic/add-some-logic.py b/ch08-conditional-logic/add-some-logic.py new file mode 100644 index 0000000..f469c90 --- /dev/null +++ b/ch08-conditional-logic/add-some-logic.py @@ -0,0 +1,14 @@ +''' +1. Figure out what the result will be (True or False) when evaluating +the following expressions, then type them into the interactive win- +dow to check your answers: +• (1 <= 1) and (1 != 1) ==> False +• not (1 != 2) ==> False +• ("good" != "bad") or False ==> True +• ("good" != "Good") and not (1 == 1) ==> False +2. Add parentheses where necessary so that each of the following ex- +pressions evaluates to True: +• False == not True +• True and False == True and False +• not True and "A" == "B" ==> not (True and "A" == "B") +''' diff --git a/ch08-conditional-logic/break-out-of-the-pattern.py b/ch08-conditional-logic/break-out-of-the-pattern.py new file mode 100644 index 0000000..723c1fd --- /dev/null +++ b/ch08-conditional-logic/break-out-of-the-pattern.py @@ -0,0 +1,69 @@ + +print("Example using 'break'") +for n in range(4): + if n == 2: + break + print(n) + +print(f"Finished with n = {n}\n") + +print("Example using 'continue'") +for i in range(4): + if i == 2: + continue + print(i) + +print(f"Finished with i = {i}") + +# for ... else loop + +user_phrase = input("Enter a phrase to evaluate: ") + +for character in user_phrase: + if character == "X": + break +else: + print("There was no 'X' in the phrase") + +print("Final statement") + +# practical example for a 'for ... else' loop + +for n in range(3): + password = input("Password: ") + if password == "I<3Bieber": + break + print("Password is incorrect.") +else: + print("Suspicious activity. The authorities have been alerted.") + + +# review exercises + +''' +1. Using break, write a program that repeatedly asks the user for some +input and quits only if the user enters "q" or "Q". +''' + +escape = 'q' +prompt = "Please enter some text: " +user_input = "" + +while True: + user_input = input(prompt).lower() + if user_input == escape: + break + +print("You did escape") + +''' +2. Using continue, write a program that loops over the numbers 1 to +50 and prints all numbers that are not multiples of 3. +''' + +print("\nHere are the number from 1 to 50 except the multiples of 3") + +for num in range(1,51): + if num % 3 == 0: + continue + print(num) diff --git a/ch08-conditional-logic/challenge-simulate-a-coint-toss-experiment.py b/ch08-conditional-logic/challenge-simulate-a-coint-toss-experiment.py new file mode 100644 index 0000000..e69de29 diff --git a/ch08-conditional-logic/coinf-flip.py b/ch08-conditional-logic/coinf-flip.py new file mode 100644 index 0000000..02eb200 --- /dev/null +++ b/ch08-conditional-logic/coinf-flip.py @@ -0,0 +1,21 @@ +import random + +def coin_flip(): + """Randomly return 'heads' or 'tails'""" + if random.randint(0, 1) == 0: + return 'heads' + else: + return 'tails' + +# First initialize the taallies to 0 +heads_tally = 0 +tails_tally = 0 + +for trial in range(50_000): + if coin_flip() == 'heads': + heads_tally = heads_tally + 1 + else: + tails_tally = tails_tally +1 + +ratio = heads_tally / tails_tally +print(f"The ratio of head to tails is {ratio}") diff --git a/ch08-conditional-logic/compare-values.py b/ch08-conditional-logic/compare-values.py new file mode 100644 index 0000000..c388d75 --- /dev/null +++ b/ch08-conditional-logic/compare-values.py @@ -0,0 +1,21 @@ +''' +1. For each of the following conditional expressions, guess whether +they evaluate to True or False. Then type them into the interactive +window to check your answers: +• 1 <= 1 True +• 1 != 1 False +• 1 != 2 True +• "good" != "bad" True +• "good" != "Good" True +• 123 == "123" False + + +2. For each of the following expressions, fill in the blank (indicated by +__) with an appropriate Boolean comparator so that the expression +evaluates to True: +• 3 __ 4 +• 10 __ 5 +• "jack" __ "jill" +• 42 __ "42" +''' + diff --git a/ch08-conditional-logic/control-the-flow-review-exercise.py b/ch08-conditional-logic/control-the-flow-review-exercise.py new file mode 100644 index 0000000..955d11d --- /dev/null +++ b/ch08-conditional-logic/control-the-flow-review-exercise.py @@ -0,0 +1,39 @@ +''' +1. Write a program that prompts the user to enter a word using the +input() function and compares the length of the word to the num- +ber five. The program should display one of the following outputs, +depending on the length of the user’s input: +• "Your input is less than 5 characters long" +• "Your input is greater than 5 characters long" +• "Your input is 5 characters long" +''' + +goal = 5 +user_input = input("Enter a word: ") +input_len = len(user_input) + + +if input_len < goal: + print(f"Your input is less than {goal} characters long") +elif input_len > goal: + print(f"Your input is greater than {goal} characters long") +else: + print(f"Your input is {goal} characters long") + + +''' +2. Write a program that displays "I'm thinking of a number between 1 +and 10. Guess which one." Then use input() to get a number from +the user. If the user inputs the number 3, then the program should +display "You win!" For any other input, the program should display +"You lose." +''' + +num = 3 +print("\nI'm thinking of a number between 1 and 10. Guess which one.") +user_guess = int(input("What's your guess? ")) + +if user_guess == num: + print("You win!") +else: + print("You lose.") diff --git a/ch08-conditional-logic/control-the-flow.py b/ch08-conditional-logic/control-the-flow.py new file mode 100644 index 0000000..f35d6fc --- /dev/null +++ b/ch08-conditional-logic/control-the-flow.py @@ -0,0 +1,136 @@ +div_line = 50 * '#' + +print(f"\n{div_line}\nThe Start of sample 1\n{div_line}\n") + +if 2 + 2 == 4: + print("2 and 2 is 4") + +if 2 + 2 == 5: + print("Is this the mirror universe?") + + + + +# selective code execution on condition +# if keyword +print(f"\n{div_line}\nThe Start of 'if' sample\n{div_line}\n") + +grade = 40 + +if grade >= 70: + print("You passed the class!") + +if grade < 70: + print("You did not pass the class :( ") + +print("Thank you for attending.") + +# if - else keywords +print(f"\n{div_line}\nThe Start of 'if - else' sample\n{div_line}\n") + +if grade >= 70: + print("You passed the class!") +else: + print("You did not pass the class :( ") + +print("Thank you for attending.") + +# elif keyword +print(f"\n{div_line}\nThe Start of 'elif' sample\n{div_line}\n") + +grade = 85 + +if grade >= 90: + print("You passed the class with an A.") +elif grade >= 80: + print("You passed the class with an B.") +elif grade >= 70: + print("You passed the class with a C.") +else: + print("You did not pass the class :( ") + +print("Thank you for attending") + + +# nested if statements +print(f"\n{div_line}\nThe Start of nested if statements sample\n{div_line}\n") + +sport = input("Enter a sport: ") +p1_score = int(input("Enter player 1 score: ")) +p2_score = int(input("Enter player 2 score: ")) + +# 1 basketball + +if sport.lower() == "basketball": + if p1_score == p2_score: + print("The game is a draw.") + elif p1_score > p2_score: + print("Player 1 wins.") + else: + print("Player 2 wins.") + +# 2 golf +elif sport.lower() == "golf": + if p1_score == p2_score: + print("The game is a draw.") + elif p1_score < p2_score: + print("Player 1 wins.") + else: + print("Player 2 wins.") + +# 2 other sports +else: + print("Unknown sport") + + +# refactor to reduce complexity + +print(f"\n{div_line}\nThe Start of refactored nested if statements sample\n{div_line}\n") + +sport = input("Enter a sport: ") +p1_score = int(input("Enter player 1 score: ")) +p2_score = int(input("Enter player 2 score: ")) + +# same score is a draw regardless of the sport +if p1_score == p2_score: + print("The game is a draw.") + +elif sport.lower() == "basketball": + if p1_score > p2_score: + print("Player 1 wins.") + else: + print("Player 2 wins.") + +# 2 golf +elif sport.lower() == "golf": + if p1_score < p2_score: + print("Player 1 wins.") + else: + print("Player 2 wins.") + +# 2 other sports +else: + print("Unknown sport") + +# refactor to use compount conditional expressions: +print(f"\n{div_line}\nThe Start of refactored code using compound conditional\n" + + f"expressions sample\n{div_line}\n") + +sport = input("Enter a sport: ") +p1_score = int(input("Enter player 1 score: ")) +p2_score = int(input("Enter player 2 score: ")) + +sport = sport.lower() + +if p1_score == p2_score: + print("The game is a draw") +elif (sport == "basketball") or (sport == "golf"): + p1_wins_bball = (sport == "basketball") and (p1_score > p2_score) + p1_wins_golf = (sport == "golf") and (p1_score < p2_score) + p1_wins = p1_wins_bball or p1_wins_golf + if p1_wins: + print("Player 1 wins.") + else: + print("Player 2 wins.") +else: + print("Unknown sport") diff --git a/ch08-conditional-logic/dice.py b/ch08-conditional-logic/dice.py new file mode 100644 index 0000000..7474e08 --- /dev/null +++ b/ch08-conditional-logic/dice.py @@ -0,0 +1,10 @@ +import random + +def dice(): + ''' Throw a dice and return the result''' + result = random.randint(1, 6) + print(result) + return result + +for num in range(0, 10): + dice() diff --git a/ch08-conditional-logic/factors.py b/ch08-conditional-logic/factors.py new file mode 100644 index 0000000..408c57a --- /dev/null +++ b/ch08-conditional-logic/factors.py @@ -0,0 +1,13 @@ +''' +Write a program called factors.py that asks the user to input a posi- +tive integer and then prints out the factors of that number. +''' + +user_input = int(input("Enter a positive integer: ")) + +for num in range(1, user_input + 1): + if user_input % num == 0: + print(f"{num} is a factor of {user_input}") + + +# did it! the wording in the sample solution is a bit different diff --git a/ch08-conditional-logic/fair-coin.py b/ch08-conditional-logic/fair-coin.py new file mode 100644 index 0000000..d13b0d2 --- /dev/null +++ b/ch08-conditional-logic/fair-coin.py @@ -0,0 +1,19 @@ +import random + +def toss(): + if random.randint(0,1) == 0: + return 'heads' + else: + return 'tails' + +heads_tally = 0 +tails_tally = 0 + +for trial in range(10_000): + if toss() == 'heads': + heads_tally = heads_tally + 1 + else: + tails_tally = tails_tally + 1 + +ratio = heads_tally / tails_tally +print(f"The ratio is {ratio}") diff --git a/ch08-conditional-logic/recover-from-errors.py b/ch08-conditional-logic/recover-from-errors.py new file mode 100644 index 0000000..028aa76 --- /dev/null +++ b/ch08-conditional-logic/recover-from-errors.py @@ -0,0 +1,67 @@ +try: + number = int(input("Enter an integer: ")) +except ValueError: + print("That was not an integer") + +print(number) + + +# multiple exception +def divide(num1, num2): + try: + print(num1 / num2) + except (TypeError, ZeroDivisionError): + print("encountered a problem") + + +divide(3, 6) +divide(4, 0) +divide(6, 's') + + +def divide2(num1, num2): + try: + print(num1 / num2) + except TypeError: + print("Both arguments must be numbers") + except ZeroDivisionError: + print("num2 must not be 0") + +divide2(3, 6) +divide2(4, 0) +divide2(6, 's') + +# review exercises + +''' +1. Write a program that repeatedly asks the user to input an integer. +If the user enters something other than an integer, then the +program should catch the ValueError and display the message "Try +again." +Once the user enters an integer, the program should display +the number back to the user and end without crashing. +''' + +keep_running = True + +while(keep_running): + try: + num = int(input("Enter an integer: ")) + except ValueError: + print("Try again") + continue + keep_running = False + +print(num) + + +''' +2. Write a program that asks the user to input a string and an integer +n, then displays the character at index n in the string. +Use error handling to make sure the program doesn’t crash +if the user enters something other than an integer or if the index +is out of bounds. The program should display a different message +depending on which error occurs. +''' + + diff --git a/ch08-conditional-logic/review-exercises.py b/ch08-conditional-logic/review-exercises.py new file mode 100644 index 0000000..127a1b7 --- /dev/null +++ b/ch08-conditional-logic/review-exercises.py @@ -0,0 +1,30 @@ +''' +Docstring for ch08-conditional-logic.review-exercises + +1. Write a function called roll() that uses randint() to simulate rolling +a fair die by returning a random integer between 1 and 6. + +2. Write a program that simulates ten thousand rolls of a fair die and +displays the average number rolled. +''' + +# exercise 1 + +import random + +def roll(): + ''' randomly returns an integer between 1 and 6, inclusive ''' + return random.randint(1,6) + +dice = roll() +print(dice) + +# exercise 2 + +sum_of_rolls = 0 + +for trial in range(10_000): + sum_of_rolls += roll() + +average = sum_of_rolls / 10000 +print(f"The average number rolled is {average}") \ No newline at end of file diff --git a/ch08-conditional-logic/simulate-an-election.py b/ch08-conditional-logic/simulate-an-election.py new file mode 100644 index 0000000..63ac3ae --- /dev/null +++ b/ch08-conditional-logic/simulate-an-election.py @@ -0,0 +1,44 @@ +import random + +''' +With some help from the random module and a little conditional logic, +you can simulate an election between two candidates. +Suppose two candidates, Candidate A and Candidate B, are running +for mayor in a city with three voting regions. The most recent polls +show that Candidate A has the following chances for winning in each +region: +• Region 1: 87 percent chance of winning +• Region 2: 65 percent chance of winning +• Region 3: 17 percent chance of winning +Write a program that simulates the election ten thousand times and +prints the percentage of times in which Candidate A wins. +To keep things simple, assume that a candidate wins the election if +they win in at least two of the three regions +''' + +region1_chance = 0.87 +region2_chance = 0.65 +region3_chance = 0.17 + +simulation_runs = 10_000 +candidate_a_win_count = 0 + +def election(chance_candidate_a_wins): + """ Randomly returns 'True' or 'False' depending on the result """ + if random.random() <= chance_candidate_a_wins: + return True + else: + return False + +for election_run in range(simulation_runs): + region1_result = election(region1_chance) + region2_result = election(region2_chance) + region3_result = election(region3_chance) + + if (region1_result and region2_result) or (region1_result and region3_result) or (region2_result and region3_result): + candidate_a_win_count +=1 + +candidate_a_win_quote = candidate_a_win_count / simulation_runs * 100 + +print(f"Candidate A wins in {candidate_a_win_quote: .2f} percent of simulations") + diff --git a/ch08-conditional-logic/unfair-coin-flip.py b/ch08-conditional-logic/unfair-coin-flip.py new file mode 100644 index 0000000..0b55499 --- /dev/null +++ b/ch08-conditional-logic/unfair-coin-flip.py @@ -0,0 +1,33 @@ +import random + +# For example, unfair_coin_flip(.7) has a 70 percent chance of returning 'tails' +def unfair_coin_flip(probability_of_tails): + ''' Randomly returns 'heads' or 'tails' with a given probability 0.x of returning 'tails' ''' + if random.random() < probability_of_tails: + return 'tails' + else: + return 'heads' + +heads_tally = 0 +tails_tally = 0 + +for trial in range(10_000): + if unfair_coin_flip(.7) == "heads": + heads_tally = heads_tally + 1 + else: + tails_tally += 1 + +ratio = heads_tally / tails_tally +print(f"The ratio of heads to tails is {ratio}") + +heads_tally = 0 +tails_tally = 0 + +for trial in range(10_000): + if unfair_coin_flip(.4) == "heads": + heads_tally += 1 + else: + tails_tally += 1 + +ratio = heads_tally / tails_tally +print(f"The ratio of heads to tails is {ratio}") diff --git a/ch08-conditional-logic/unfair-coin.py b/ch08-conditional-logic/unfair-coin.py new file mode 100644 index 0000000..1379cb4 --- /dev/null +++ b/ch08-conditional-logic/unfair-coin.py @@ -0,0 +1,20 @@ +import random + +def unfair_toss(probability_of_tails): + if random.random() < probability_of_tails: + return 'tails' + else: + return 'heads' + + +heads_tally = 0 +tails_tally = 0 + +for trial in range(10_000): + if unfair_toss(0.8) == 'heads': + heads_tally += 1 + else: + tails_tally += 1 + +ratio = heads_tally / tails_tally +print(f"The ration of heads to tail is {ratio}") \ No newline at end of file diff --git a/ch09-lists-tuples-and-dictionaries/.ipynb_checkpoints/tuple-checkpoint.py b/ch09-lists-tuples-and-dictionaries/.ipynb_checkpoints/tuple-checkpoint.py new file mode 100644 index 0000000..178c17d --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/.ipynb_checkpoints/tuple-checkpoint.py @@ -0,0 +1,49 @@ +# Tuple literal +# is a tuple that is written out explicitly as a comma-separated list of values +# sourrounded by parantheses. + +my_first_tuple = (1, 2, 3) +print(type(my_first_tuple)) + +mixed_tuple = (1, 2.0, "three") +print(type(mixed_tuple)) + +empty_tuple = () +print(type(empty_tuple)) + +# create tuple with exactly one element +x = (1) +print(type(x)) + +# add a comma after the only element +x = (1,) +print(type(x)) + +# Built-in tuple() +# you can use the built-in tuple() to create a tuple from another sequence type, such as a string: +print(tuple("Python")) + +# test +print(tuple(range(1, 5))) + +vowels = ("a", "e", "i", "o", "u") + +for vowel in vowels: + print(vowel.upper()) + +# Tuple unpacking +# third but less common way of creating a tuple + +coordinates = 4.21, 9.29 +print(type(coordinates)) +print(coordinates) + +x, y = coordinates +print(f"x = {x}") +print(f"y = {y}") + +# multiple variable assignemnts in a single line +name, age, occupation = "Adisa", 34, "programmer" +print(name) +print(age) +print(occupation) \ No newline at end of file diff --git a/ch09-lists-tuples-and-dictionaries/3-nesting-copying-sorting-tuples-and-lists.py b/ch09-lists-tuples-and-dictionaries/3-nesting-copying-sorting-tuples-and-lists.py new file mode 100644 index 0000000..e9dee4c --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/3-nesting-copying-sorting-tuples-and-lists.py @@ -0,0 +1,136 @@ +# Nesting +two_by_two = [[1, 2], [3, 4]] + +# two_by_two has length 2 +print(len(two_by_two)) + +# both elements of two_by_two are lists +print(two_by_two[0]) +print(two_by_two[1]) + +print("two_by_two[1]") +print(two_by_two[1]) + +print("two_by_two[1][0]") +print(two_by_two[1][0]) +print() +# Copying + +print("*" * 50) +animals = ["lion", "tiger", "frumious Bandersnatch"] +# shallow copy, copies the reference to the same object. +# A variable name is really just a reference to a specific location in computer memory. +large_cats = animals +large_cats.append("Tigger") + +print("animals after large_cats = animals and large_cats.append('Tigger')") +print(animals) + +# to get an independent kopy of the animals list, you can use slice notation to return a new list with +# the same values +animals = ["lion", "tiger", "frumious Bandersnatch"] +large_cats = animals[:] +large_cats.append("leopard") + +print("large_cats created with slice notation animals[:] and after appending a new animal") +print(large_cats) + +print("Animals to show it is not affected by changes to large_cats") +print(animals) + +import copy +mamals = copy.deepcopy(animals) +print("New list created using copy.deepcopy(list)") +print(mamals) +print("Add new element to new list") +mamals.append("lynx") +print("Result after adding new animal to mamals") +print(mamals) +print("Animals list after editing the mamals list copy of animals") +print(animals) +print() +# Sorting +# .sort() sorts all items in ascending order. By default, the list is sorted in alphabetical or numerical order +# depending on the type of elements in the list + +# list of strings are sorted alphabetically +print("*" * 50) +print('colors = ["red", "yellow", "green", "blue"]') +colors = ["red", "yellow", "green", "blue"] +colors.sort() +print(colors) +print() +# list of numbers are sorted numerically +numbers = [1, 10, 5, 3] +print("numbers = [1, 10, 5, 3]") +print(numbers) +print("numbers.sort()") +numbers.sort() +print(numbers) + +# sort() has an optional parameter called key that can be used to adjust how the list gets sorted +print() +print("colors.sort(key=len)") +colors.sort(key=len) +print(colors) +print() +print("*" * 50) +# user-defined function to key +def get_second_element(item): + """ Returns the second element of item passed in """ + return item[1] + +items = [(4, 1), (1, 2), (-9, 0)] +print("Items before sorting") +print(items) +items.sort(key=get_second_element) +print("Items after sorting with user-defined 'get_second_element' as key") +print(items) + +print() +print("*" * 50) + +# Review Exercise + +""" +1. Create a tuple called data with two values. The first value should +be the tuple (1, 2), and the second value should be the tuple (3, +4). +""" +data = ((1, 2), (3, 4)) +print(data) + +""" +2. Write a for loop that loops over data and prints the sum of each +nested tuple. The output should look like this: +Row 1 sum: 3 +Row 2 sum: 7 +""" +counter = 1 + +for element in data: + print(f"Row {counter} sum: {sum(element)}") + counter += 1 + +""" +3. Create the list [4, 3, 2, 1] and assign it to the variable numbers. +""" +numbers = list(range(4,0,-1)) +print(numbers) + +""" +4. Create a copy of the numbers list using the [:] slice notation. +""" +copy_numbers = numbers[:] +print(copy_numbers) + +""" +5. Sort the numbers list in numerical order using .sort() +""" +numbers.sort() +print(numbers) +print(copy_numbers) + +another_copy = numbers[-1::-1] +print("An other copy") +print(another_copy) diff --git a/ch09-lists-tuples-and-dictionaries/basic-list-operations.py b/ch09-lists-tuples-and-dictionaries/basic-list-operations.py new file mode 100644 index 0000000..f852093 --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/basic-list-operations.py @@ -0,0 +1,23 @@ +# indexing and slicing +numbers = [1, 2, 3, 4] +print(f"The original numbers list: {numbers}") +print("Next the output of numbers[1]:") +print(numbers[1]) + +new_numbers = numbers[1:3] +print(f"The new list from the original list using slice notation 'numbers[1:3]'") +print(new_numbers) + +# like in tuples we can use 'in' to check for the existence of list elements +# Check existence of an element +print("Test for 'Bob' in numbers") +print("Bob" in numbers) + +# personal test how to handle numbers within in check +print(3 in numbers) + +# iterate lists, print only even numbers +print("Lists are iterable. Print only the even number from the list") +for number in numbers: + if number % 2 == 0: + print(number) \ No newline at end of file diff --git a/ch09-lists-tuples-and-dictionaries/capital.py b/ch09-lists-tuples-and-dictionaries/capital.py new file mode 100644 index 0000000..b24cd28 --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/capital.py @@ -0,0 +1,52 @@ +capitals_dict = { + "Alabama": "Montgomery", + "Alaska": "Juneau", + "Arizona": "Phoenix", + "Arkansas": "Little Rock", + "California": "Sacramento", + "Colorado": "Denver", + "Connecticut": "Hartford", + "Delaware": "Dover", + "Florida": "Tallahassee", + "Georgia": "Atlanta", + "Hawaii": "Honolulu", + "Idaho": "Boise", + "Illinois": "Springfield", + "Indiana": "Indianapolis", + "Iowa": "Des Moines", + "Kansas": "Topeka", + "Kentucky": "Frankfort", + "Louisiana": "Baton Rouge", + "Maine": "Augusta", + "Maryland": "Annapolis", + "Massachusetts": "Boston", + "Michigan": "Lansing", + "Minnesota": "Saint Paul", + "Mississippi": "Jackson", + "Missouri": "Jefferson City", + "Montana": "Helena", + "Nebraska": "Lincoln", + "Nevada": "Carson City", + "New Hampshire": "Concord", + "New Jersey": "Trenton", + "New Mexico": "Santa Fe", + "New York": "Albany", + "North Carolina": "Raleigh", + "North Dakota": "Bismarck", + "Ohio": "Columbus", + "Oklahoma": "Oklahoma City", + "Oregon": "Salem", + "Pennsylvania": "Harrisburg", + "Rhode Island": "Providence", + "South Carolina": "Columbia", + "South Dakota": "Pierre", + "Tennessee": "Nashville", + "Texas": "Austin", + "Utah": "Salt Lake City", + "Vermont": "Montpelier", + "Virginia": "Richmond", + "Washington": "Olympia", + "West Virginia": "Charleston", + "Wisconsin": "Madison", + "Wyoming": "Cheyenne", +} \ No newline at end of file diff --git a/ch09-lists-tuples-and-dictionaries/challenge-capital-city-loop.py b/ch09-lists-tuples-and-dictionaries/challenge-capital-city-loop.py new file mode 100644 index 0000000..88736a2 --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/challenge-capital-city-loop.py @@ -0,0 +1,38 @@ +""" Challenge Tuples, Lists, and Dictionaries (p269) """ +import random +import capital + +# my first try +# states = list(capital.capitals_dict.keys()) +# random_state = random.choice(states) +# random_capital = capital.capitals_dict[random_state] + +# sample solution +random_state, random_capital = random.choice(list(capital.capitals_dict.items())) + +## my try +# guess = "" + +# while guess.lower() != random_capital.lower(): +# guess = input(f"What is the capital of {random_state}?") + +# if guess.lower() == "exit": +# print(random_capital) +# print("Goodbye") +# break + +# if guess.lower() == random_capital.lower(): + # print("Correct") + + +# sample + +while True: + guess = input(f"What is the capital of '{random_state}'? ").lower() + if guess == "exit": + print(f"The capital of '{random_state}' is '{random_capital}'.") + print("Goodbye") + break + elif guess == random_capital.lower(): + print("Correct! Nice job.") + break \ No newline at end of file diff --git a/ch09-lists-tuples-and-dictionaries/challenge-list-of-lists.py b/ch09-lists-tuples-and-dictionaries/challenge-list-of-lists.py new file mode 100644 index 0000000..f5ad89a --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/challenge-list-of-lists.py @@ -0,0 +1,123 @@ +# 9.4 Challenge: List of lists +""" +9.4. Challenge: List of lists +9.4 Challenge: List of lists +Write a program that contains the following lists of lists: +universities = [ +['California Institute of Technology', 2175, 37704], +['Harvard', 19627, 39849], +['Massachusetts Institute of Technology', 10566, 40732], +['Princeton', 7802, 37000], +['Rice', 5879, 35551], +['Stanford', 19535, 40569], +['Yale', 11701, 40500] +] +Define a function, enrollment_stats(), with a single parameter. This +parameter should be a list of lists in which each individual list contains +three elements: +1. The name of a university +2. The total number of enrolled students +3. The annual tuition fees +enrollment_stats() should return two lists, the first containing all the +student enrollment values and the second containing all the tuition +fees. +Next, define two functions, mean() and median(), that take a single list +argument and return the mean or median of the values in each list, +respectively. +Using universities, enrollment_stats(), mean(), and median(), calculate +the total number of students, the total tuition, the mean and median +numbers of students, and the mean and median tuition values. +256 +9.5. Challenge: Wax Poetic +Finally, output all values and format the output so that it looks like +this: +****************************** +Total students: 77,285 +Total tuition: $ 271,905 +Student mean: 11,040.71 +Student median: 10,566 +Tuition mean: $ 38,843.57 +Tuition median: $ 39,849 +****************************** +You can пnd the solutions to this code challenge and many other bonus +resources online at realpython.com/python-basics/resources +""" + +universities = [ + ["California Institute of Technology", 2175, 37704], + ["Harvard", 19627, 39849], + ["Massachusetts Institute of Technology", 10566, 40732], + ["Princeton", 7802, 37000], + ["Rice", 5879, 35551], + ["Stanford", 19535, 40569], + ["Yale", 11701, 40500] +] + +def enrollment_stats(university_list): + """ Returns two lists, the first containing all the student enrollment values and the + second containing all the tuition fees. """ + student_enrollments = [uni[1] for uni in university_list] + print(student_enrollments) + tuition_fees = [uni[2] for uni in university_list] + return student_enrollments, tuition_fees + +def mean(item_list): + """ Returns the mean of the values in the list """ + result = 0 + + for item in item_list: + result += item + + return result / len(item_list) + + + +def median(item_list): + """ Returns the median of the values in the list """ + items = item_list[:] + number_of_items = len(items) + items.sort() + if number_of_items % 2 != 0: + index = number_of_items // 2 + return items[index] + index = number_of_items // 2 + median = (items[index - 1] + items[index]) / 2 + return median + + + +# variable for output +total_students = 0 +total_tuition = 0 + +student_mean = 0 +student_median = 0 + +tuition_mean = 0 +tuition_median = 0 + +# get data from functions +students_and_tuition_lists = enrollment_stats(universities) +students = students_and_tuition_lists[0] +tuitions = students_and_tuition_lists[1] + +total_students = sum(students) +total_tuition = sum(tuitions) + +student_mean = mean(students) +tuition_mean = mean(tuitions) + +student_median = median(students) +tuition_median = median(tuitions) + +#print(enrollment_stats(universities)) + +print("*" * 30) +print(f"Total students: {total_students:,}") +print(f"Total tuition: $ {total_tuition:,}") +print() +print(f"Student mean: {student_mean:,.2f}") +print(f"Student median: {student_median:,}") +print() +print(f"Tuition mean: $ {tuition_mean:,.2f}") +print(f"Tuition median: $ {tuition_median :,.2F}") diff --git a/ch09-lists-tuples-and-dictionaries/challenge-wax-poetic.py b/ch09-lists-tuples-and-dictionaries/challenge-wax-poetic.py new file mode 100644 index 0000000..59a5a6c --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/challenge-wax-poetic.py @@ -0,0 +1,112 @@ +import random + +# better overview of lists if one element per line +nouns = [ + "fossil", + "horse", + "aardvark", + "judge", + "chef", + "mango", + "extrovert", + "gorilla" + ] +verbs = [ + "kicks", + "jingles", + "bounces", + "slurps", + "meows", + "explodes", + "curdles" + ] +adjectives = [ + "furry", + "balding", + "incredulous", + "fragrant", + "exuberant", + "glistening" + ] +prepositons = [ + "against", + "after", + "into", + "beneath", + "upon", + "for", + "in", + "like", + "over", + "within" + ] +adverbs = [ + "curiously", + "extravagantly", + "tantalizingly", + "furiously", + "sensuously" + ] + +def get_random_elements(list, count): + """ Function returns count number of random elements from the list """ + result = [] + for i in range(count): + result.append(random.choice(list)) + return result + +# sample how to use random.choice() +# random_element = random.choice(["a", "b", "c"]) +# print(random_element) + +noun_count = 3 +verb_count = 3 +adjective_count = 3 +preposition_count = 2 + +# output structure +""" +{A/An} {adj1} {noun1} + +{A/An} {adj1} {noun1} {verb1} {prep1} the {adj2} {noun2} +{adverb1}, the {noun1} {verb2} +the {noun2} {verb3} {prep2} a {adj3} {noun3} +""" + +# # get random elements +# random_nouns = get_random_elements(nouns, noun_count) +# random_verbs = get_random_elements(verbs, verb_count) +# random_adjectives = get_random_elements(adjectives, adjective_count) +# random_prepositions = get_random_elements(prepositons, preposition_count) + +# # split lists +# noun1, noun2, noun3 = random_nouns +# verb1, verb2, verb3 = random_verbs +# adj1, adj2, adj3 = random_adjectives +# prep1, prep2 = random_prepositions +# adverb1 = random.choice(adverbs) + +# combine the get random elements with splitting the lists +noun1, noun2, noun3 = get_random_elements(nouns, noun_count) +verb1, verb2, verb3 = get_random_elements(verbs, verb_count) +adj1, adj2, adj3 = get_random_elements(adjectives, adjective_count) +prep1, prep2 = get_random_elements(prepositons, preposition_count) +adverb1 = random.choice(adverbs) + +article = "A" +vowels = "aeiou" + +if adj1[0] in vowels: + article = "An" + +# print output +print(f"""{article} {adj1} {noun1} + +{article} {adj1} {noun1} {verb1} {prep1} the {adj2} {noun2} +{adverb1}, the {noun1} {verb2} +the {noun2} {verb3} {prep2} a {adj3} {noun3}""") + +# I did not take into account, that random.choice might draft the same word +# multiple times. +# the whole random and creation act could be in the new function. +# first try 17.03.2026 diff --git a/ch09-lists-tuples-and-dictionaries/dictionary-review-exercise.py b/ch09-lists-tuples-and-dictionaries/dictionary-review-exercise.py new file mode 100644 index 0000000..3f26cf9 --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/dictionary-review-exercise.py @@ -0,0 +1,66 @@ +""" Review Exercise p269""" + +""" +1. Create an empty dictionary named captains. +""" +captains = {} + +""" +2. Using square bracket notation, enter the following data into the +dictionary one item at a time: +• 'Enterprise': 'Picard' +• 'Voyager': 'Janeway' +• 'Defiant': 'Sisko' +""" +captains["Enterprise"] = "Picard" +captains["Voyager"] = "Janeway" +captains["Defiant"] = "Sisko" + +""" +3. Write two if statements that check if "Enterprise" and "Discovery" +exist as keys in the dictionary. Set their values to "unknown" if the +key does not exist. +""" + +ships = ("Enterprise", "Discovery") + +for ship in ships: + if not ship in captains: + captains[ship] = "unknown" + + +""" +4. Write a for loop to display the ship and captain names contained +in the dictionary. For example, the output should look something +like this: +The Enterprise is captained by Picard. +""" +for starship, captain in captains.items(): + print(f"The {starship} is captained by {captain}") + +""" +5. Delete "Discovery" from the dictionary. +""" +del captains["Discovery"] + +""" +6. Bonus: Make the same dictionary by using dict() and passing in +the initial values when you first create the dictionary. +""" + +captain_list = (("Enterprise", "Picard"), + ("Voyager", "Janeway"), + ("Defiant", "Sisko") + ) + +captains = dict(captain_list) +print(captains) + +# solution +captains = dict( + [ + ("Enterprise", "Picard"), + ("Voyager", "Janeway"), + ("Defiant", "Sisko jr.") + ] +) \ No newline at end of file diff --git a/ch09-lists-tuples-and-dictionaries/list-methods.py b/ch09-lists-tuples-and-dictionaries/list-methods.py new file mode 100644 index 0000000..2af3c34 --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/list-methods.py @@ -0,0 +1,79 @@ +# list.insert() takes an index i and a value x and inserts the value x at +# index i in the list: + +colors = ["red", "yellow", "green", "blue"] +print("Original list") +print(colors) + +# insert "orange" into the second position +colors.insert(1, "orange") +print('After colors.insert(1, "orange")') +print(colors) + +# if value for index parameter of .insert() is larger than the greates index +# in the list, then the value is inserted at the end of the list: +colors.insert(10, "violet") +print("after colors.insert(10, 'violet')") +print(colors) + + +# You can also use negative indices with .insert() +# i = -1 inserts the value x to the currently last index. +# which results in moving the existing last value to the right. staying last +colors.insert(-1, "indigo") +print('After colors.insert(-1, "indigo")') +print(colors) + + +# Remove value from specified index list.pop() takes one parameter, an index i +# the value that is removed is returned by the method +color = colors.pop(3) +print("colors.pop(3) returned and removed: " + (color)) + +print("colors List after using colors.pop(3)") +print(colors) + +# remove the last object from the list with pop(-1) +# .pop() without a value removes the last item in the list: +color = colors.pop(-1) +print("colors.pop(-1) returned and removed: " + (color)) + +print("colors List after using colors.pop(-1)") +print(colors) + +# list.append() +# calling .appen() increases the length of the list by one and inserts the value into the final slot. +colors.append("pink") +print(colors) + +# alternative way to add 'pink' to the end of the list +colors.pop() +print(colors) + +colors.insert(len(colors), "pink") +print(colors) + +# list.extend() method is used to add several new elements to the end of a list +colors.extend(["violet", "grey", "amber"]) +print(colors) + +# excurse to list-of-numbers.py + +# List comprehensions +print("Create a tuple of numbers:") +my_numbers = (1, 2, 3, 4, 5) +print(my_numbers) +print("use list comprehensions") +print("squares = [num**2 for num in my_numbers]") +squares = [num**2 for num in my_numbers] +print("Result:") +print(squares) + +# list comprehensions are commonly used to convert values in a list to a different type +print("\nList Comprehensions") +print("From string input to floats using list comprehension") +str_numbers = ["1.5", "2.3", "5.25"] +print(str_numbers) +print("float_numbers = [float(value) for value in str_numbers]") +float_numbers = [float(value) for value in str_numbers] +print(float_numbers) \ No newline at end of file diff --git a/ch09-lists-tuples-and-dictionaries/list-of-numbers.py b/ch09-lists-tuples-and-dictionaries/list-of-numbers.py new file mode 100644 index 0000000..e46988d --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/list-of-numbers.py @@ -0,0 +1,31 @@ +# List of numbers + +nums = [1, 2, 3, 4, 5] +print("nums = [1, 2, 3, 4, 5]") + +total = 0 +for number in nums: + total += number + +print(total) + +# a much more succinct was of doing this in Python: +print("sum([1, 2, 3, 4, 5])") +print(sum([1, 2, 3, 4, 5])) +print("sum(nums)") +print(sum(nums)) + +# two other useful built-in functions for working with numers are +# min() and max() +print("min(nums):") +print(min(nums)) +print("max(nums):") +print(max(nums)) + +# sum(), min(), and max() also work with tuples: +nums = (1, 2, 3, 4, 5) +print("sum((1, 2, 3, 4, 5))") +print(sum((1, 2, 3, 4, 5))) +print(min(nums)) +print("max(nums):") +print(max(nums)) diff --git a/ch09-lists-tuples-and-dictionaries/list-review-exercises.py b/ch09-lists-tuples-and-dictionaries/list-review-exercises.py new file mode 100644 index 0000000..f8c54fb --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/list-review-exercises.py @@ -0,0 +1,47 @@ +""" +1. Create a list named food with two elements, "rice" and "beans". +""" +food = ["rice", "beans"] +print(food) + +""" +2. Append the string "broccoli" to food using .append(). +""" +food.append("broccoli") +print(food) + +""" +3. Add the strings "bread" and "pizza" to food using .extend(). +""" +food.extend(["bread", "pizza"]) +print(food) + +""" +4. Print the first two items in the food list using print() and slice no- +tation. +""" +print(food[:2]) + +""" +5. Print the last item in food using print() and index notation. +""" +print(food[-1]) + +""" +6. Create a list called breakfast from the string "eggs, fruit, orange +juice" using the string .split() method. +""" +str_breakfast = "eggs, fruit, orange juice" +breakfast = str_breakfast.split(",") + +""" +7. Verify that breakfast has three items using len(). +""" +print(len(breakfast)) + +""" +8. Create a new list called lengths using a list comprehension that con- +tains the lengths of each string in the breakfast list. +""" +lengths = [len(value) for value in breakfast] +print(lengths) diff --git a/ch09-lists-tuples-and-dictionaries/lists-are.py b/ch09-lists-tuples-and-dictionaries/lists-are.py new file mode 100644 index 0000000..09032e1 --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/lists-are.py @@ -0,0 +1,51 @@ +# Starting with lists, the first mutable squence we encounter + +colors = ["red", "yellow", "green", "blue"] +print(type(colors)) + +print(colors) + +# a list can consist of elements of different datatypes +sample_list = [ 1, 2.0, "three"] +print(type(sample_list)) +print(sample_list) + +# create a list using the built-in list() +# create a list from a tuple + +print(list((1, 2, 4,))) + +# create a list from a string +print(list("Python")) + +# create a list from a string using split() +groceries = "eggs, milk, cheese, chocolate" +grocery_list = groceries.split(", ") +print(grocery_list) + +# The string argument passed to .split() is called the separator +# by changing the separator, you can split strings into lists in +# numerous ways: + +# split string on semicolon +print("a;b;c".split(";")) + +# split string on spaces +print("The quick brown fox".split(" ")) + +# split string on multiple characters +# .split() always returns a list whose length is one more than the number +# of separators contained in the string. The separator "ba" appears twice, +# so the list returned by split() has three elements. +print("abbaabba".split("ba")) + +# it the separator is not contained in the string at all, then .split() +# returns a list with the string as its only element +print("abbaabba".split("c")) + +""" +In all, you’ve seen three ways to create a list: +1. A list literal +2. The built-in list() +3. The string .split() method +""" diff --git a/ch09-lists-tuples-and-dictionaries/store-relationships-in-dictionaries.py b/ch09-lists-tuples-and-dictionaries/store-relationships-in-dictionaries.py new file mode 100644 index 0000000..9c0c14e --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/store-relationships-in-dictionaries.py @@ -0,0 +1,87 @@ +""" Python Basiscs: A Practical Introduction - 9.6 Store Relationships in Dictionaries """ +capitals = { + "California": "Sacramento", + "New York": "Albany", + "Texas": "Austin" +} + +key_value_pairs = ( + ("California", "Sacramento"), + ("New York", "Albany"), + ("Texas", "Austin") +) + +capitals2 = dict(key_value_pairs) + +print(capitals) +print(key_value_pairs) +print(capitals2) + +# access dictionary values +print("Access capital of Texas") +print("capitals[\"Texas\"]") +print(capitals["Texas"]) + +# adding and removing values in a dictionary +capitals["Colorado"] = "Denver" +print(capitals) + +del capitals["Texas"] +print(capitals) + +#checking the existence of dictionary keys +try: + print(capitals["Arizona"]) +except KeyError: + print("Key not found") + +result = "Arizona" in capitals +print(f"Arizona in capitals? {result}") + +result = "California" in capitals +print(f"California in capitals? {result}") + +if "Arizona" in capitals: + print(f"The capital of Arizona is {capitals['Arizona']}.") + +# in checks for the existence of keys not values! +print("Sacramento in capitals?", "Sacramento" in capitals) + +# iterating over dictionaries + +for key in capitals: + print(f"The capital of {key} is {capitals[key]}") + +print(capitals.items()) + +print(type(capitals.items())) + +for state, capital in capitals.items(): + print(f"The capital of {state} is {capital}.") + +# dictionary keys and immutability +capitals[50] = "Honolulu" + +print(capitals) + +# nested dictionaries + +states = { + "California": { + "capital": "Sacramento", + "flower": "California Poppy" + }, + "New York": { + "capital": "Albany", + "flower": "Rose" + }, + "Texas": { + "capital": "Austin", + "flower": "Bluebonnet" + } +} + +print(states["Texas"]) + +# get the Texas state flower +print(states["Texas"]["flower"]) \ No newline at end of file diff --git a/ch09-lists-tuples-and-dictionaries/tuple.py b/ch09-lists-tuples-and-dictionaries/tuple.py new file mode 100644 index 0000000..d24e7e4 --- /dev/null +++ b/ch09-lists-tuples-and-dictionaries/tuple.py @@ -0,0 +1,138 @@ +# Tuple literal +# is a tuple that is written out explicitly as a comma-separated list of values +# sourrounded by parantheses. + +my_first_tuple = (1, 2, 3) +print(type(my_first_tuple)) + +mixed_tuple = (1, 2.0, "three") +print(type(mixed_tuple)) + +empty_tuple = () +print(type(empty_tuple)) + +# create tuple with exactly one element +x = (1) +print(type(x)) + +# add a comma after the only element +x = (1,) +print(type(x)) + +# Built-in tuple() +# you can use the built-in tuple() to create a tuple from another sequence type, such as a string: +print(tuple("Python")) + +# test +print(tuple(range(1, 5))) + +vowels = ("a", "e", "i", "o", "u") + +for vowel in vowels: + print(vowel.upper()) + +# Tuple unpacking +# third but less common way of creating a tuple + +coordinates = 4.21, 9.29 +print(type(coordinates)) +print(coordinates) + +x, y = coordinates +print(f"x = {x}") +print(f"y = {y}") + +# multiple variable assignemnts in a single line +# NOTE: Assigning more than two or three variables this way can make it +# difficult to tell which value is assigned to which variable name! +name, age, occupation = "Adisa", 34, "programmer" +print(name) +print(age) +print(occupation) + +# The number of names and the number of values must be equal + +try: + a, b, c, d = 1, 2, 3 +except ValueError: + print("ValueError exception occured: ", ValueError.__doc__) + +try: + a, b, c = 1, 2, 3, 4 +except ValueError: + print("ValueError exception occured: ", ValueError.__doc__) + +# checking the existence of values with 'in' + +o_result = "o" in vowels +print("o in vowels?", o_result) + +x_result = "x" in vowels +print("x in vowels?", x_result) + +# Returning multiple values from a function + +def adder_substractor(num1, num2): + ''' Returns a tuple in which the first element is the sum of the two numbers + and the second element is the difference between the two numbers''' + return (num1 + num2, num1 - num2) + +a = 3 +b = 2 + +print(adder_substractor(a, b)) + +a = 4 +b = 8 +print(adder_substractor(a, b)) + +a = 0 +print(adder_substractor(a, b)) + +# review exercises + +""" +1. Create a tuple literal named cardinal_numbers that holds the strings +"first", "second", and "third", in that order. +2. Using index notation and print(), display the string at index 1 in +cardinal_numbers. +3. In a single line of code, unpack the values in cardinal_numbers into +three new strings named position1, position2, and position3. Then +print each value on a separate line. +4. Using tuple() and a string literal, create a tuple called my_name that +contains the letters of your name. +5. Check whether the character "x" is in my_name using the in keyword. +6. Create a new tuple containing all but the first letter in my_name using +slice notation. +""" + +# 1 +cardinal_numbers = ("first", "second", "third") + +# 2 +print(cardinal_numbers[1]) + +# 3 +position1, position2, position3 = cardinal_numbers + +print(position1) +print(position2) +print(position3) + +# 4 +my_name = tuple("Sabrina") + +# 5 +contains_x = "x" in my_name +print("x in my_name?") +print(contains_x) + +# or short +print("x" in my_name) + +#6 +sliced_tuple = my_name[1:] +print(sliced_tuple) + +# or shorthand +print(my_name[1:]) \ No newline at end of file diff --git a/exercism.org/armstrong_number.py b/exercism.org/armstrong_number.py new file mode 100644 index 0000000..d20bda4 --- /dev/null +++ b/exercism.org/armstrong_number.py @@ -0,0 +1,18 @@ +def is_armstrong_number(number): + original_number = number + numbers = [] + + while number > 0: + num = number % 10 + numbers.insert(0, num) + number = number // 10 + + numbers_count = len(numbers) + numbers_sum = 0 + + for member in numbers: + numbers_sum += member ** numbers_count + + return numbers_sum == original_number + +print(is_armstrong_number(5)) diff --git a/exercism.org/black_jack.py b/exercism.org/black_jack.py new file mode 100644 index 0000000..6b828b8 --- /dev/null +++ b/exercism.org/black_jack.py @@ -0,0 +1,101 @@ +"""Functions to help play and score a game of blackjack. + +How to play blackjack: https://bicyclecards.com/how-to-play/blackjack/ +"Standard" playing cards: https://en.wikipedia.org/wiki/Standard_52-card_deck +""" + +def value_of_card(card): + """Determine the scoring value of a card. + + :param card: str - given card. + :return: int - value of a given card. See below for values. + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 1 + 3. '2' - '10' = numerical value. + """ + face_cards = "JQK" + + if card in face_cards: + card = "10" + if card == "A": + card = "1" + + return int(card) + + + +def higher_card(card_one, card_two): + """Determine which card has a higher value in the hand. + + :param card_one, card_two: str - cards dealt in hand. See below for values. + :return: str or tuple - resulting Tuple contains both cards if they are of equal value. + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 1 + 3. '2' - '10' = numerical value. + """ + if value_of_card(card_one) == value_of_card(card_two): + return card_one, card_two + if value_of_card(card_one) > value_of_card(card_two): + return card_one + return card_two + + +def value_of_ace(card_one, card_two): + """Calculate the most advantageous value for an upcoming ace card. + + :param card_one, card_two: str - card dealt. See below for values. + :return: int - either 1 or 11 value of the upcoming ace card. + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 11 (if already in hand) + 3. '2' - '10' = numerical value. + """ + result = 1 + card_one = set_value_of_ace_in_hand(card_one) + card_two = set_value_of_ace_in_hand(card_two) + if value_of_card(card_one) + value_of_card(card_two) < 11: + result = 11 + + return result + + +def is_blackjack(card_one, card_two): + """Determine if the hand is a 'natural' or 'blackjack'. + + :param card_one, card_two: str - card dealt. See below for values. + :return: bool - is the hand is a blackjack (two cards worth 21). + + 1. 'J', 'Q', or 'K' (otherwise known as "face cards") = 10 + 2. 'A' (ace card) = 11 (if already in hand) + 3. '2' - '10' = numerical value. + """ + card_one = set_value_of_ace_in_hand(card_one) + card_two = set_value_of_ace_in_hand(card_two) + return value_of_card(card_one) + value_of_card(card_two) == 21 + +def can_split_pairs(card_one, card_two): + """Determine if a player can split their hand into two hands. + + :param card_one, card_two: str - cards dealt. + :return: bool - can the hand be split into two pairs? (i.e. cards are of the same value). + """ + return value_of_card(card_one) == value_of_card(card_two) + + + +def can_double_down(card_one, card_two): + """Determine if a blackjack player can place a double down bet. + + :param card_one, card_two: str - first and second cards in hand. + :return: bool - can the hand can be doubled down? (i.e. totals 9, 10 or 11 points). + """ + total_value = value_of_card(card_one) + value_of_card(card_two) + return total_value in { 9, 10, 11} + +def set_value_of_ace_in_hand(card): + """ Set the value of ace to 11 if already in hand otherwise return card """ + if card == "A": + card = "11" + return card \ No newline at end of file diff --git a/exercism.org/bob.py b/exercism.org/bob.py new file mode 100644 index 0000000..b9b9028 --- /dev/null +++ b/exercism.org/bob.py @@ -0,0 +1,16 @@ +""" Talking to a teenager simulator """ +def response(hey_bob): + """ Talking to Bob returns one of five possible answers """ + + input_minus_whitespace = str.strip(hey_bob) + + if len(input_minus_whitespace) == 0: + return "Fine. Be that way!" + if input_minus_whitespace.endswith('?') and input_minus_whitespace.isupper(): + return "Calm down, I know what I'm doing!" + if input_minus_whitespace.endswith('?'): + return "Sure." + if input_minus_whitespace.isupper(): + return "Whoa, chill out!" + return "Whatever." + diff --git a/exercism.org/card_games.py b/exercism.org/card_games.py new file mode 100644 index 0000000..deec98d --- /dev/null +++ b/exercism.org/card_games.py @@ -0,0 +1,84 @@ +"""Functions for tracking poker hands and assorted card tasks. + +Python list documentation: https://docs.python.org/3/tutorial/datastructures.html +""" + + +def get_rounds(number): + """Create a list containing the current and next two round numbers. + + :param number: int - current round number. + :return: list - current round and the two that follow. + """ + return list((number, number + 1, number + 2)) + + + +def concatenate_rounds(rounds_1, rounds_2): + """Concatenate two lists of round numbers. + + :param rounds_1: list - first rounds played. + :param rounds_2: list - second set of rounds played. + :return: list - all rounds played. + """ + return rounds_1 + rounds_2 + + + +def list_contains_round(rounds, number): + """Check if the list of rounds contains the specified number. + + :param rounds: list - rounds played. + :param number: int - round number. + :return: bool - was the round played? + """ + return number in rounds + + +def card_average(hand): + """Calculate and returns the average card value from the list. + + :param hand: list - cards in hand. + :return: float - average value of the cards in the hand. + """ + return sum(hand) / len(hand) + + + +def approx_average_is_average(hand): + """Return if the (average of first and last card values) OR ('middle' card) == calculated average. + + :param hand: list - cards in hand. + :return: bool - does one of the approximate averages equal the `true average`? + """ + calculated_average = card_average(hand) + first_last_average = card_average((hand[0], hand[-1])) + middle_index = len(hand) // 2 + middle = hand[middle_index] + + return calculated_average in {first_last_average, middle} + + + +def average_even_is_average_odd(hand): + """Return if the (average of even indexed card values) == (average of odd indexed card values). + + :param hand: list - cards in hand. + :return: bool - are even and odd averages equal? + """ + even = hand[::2] + odd = hand[1::2] + + return card_average(even) == card_average(odd) + + +def maybe_double_last(hand): + """Multiply a Jack card value in the last index position by 2. + + :param hand: list - cards in hand. + :return: list - hand with Jacks (if present) value doubled. + """ + # should avoid magic numbers comment from linter... + if hand[-1] == 11: + hand[-1] = 22 + return hand diff --git a/exercism.org/collatz_conjecture.py b/exercism.org/collatz_conjecture.py new file mode 100644 index 0000000..ca11659 --- /dev/null +++ b/exercism.org/collatz_conjecture.py @@ -0,0 +1,39 @@ +""" Module to check for collatz conjecture """ + +def steps(number): + """ Calculate how many steps it takes to reach 1 using Collatz Conjecture """ + if number < 0: + raise ValueError("Only positive integers are allowed.") + return + if number == 0: + raise ValueError("0 is an invalid input.") + return + + current_value = number + count = 0 + + while current_value > 1: + if current_value % 2 == 0: + current_value = current_value / 2 + else: + current_value = current_value * 3 + 1 + count += 1 + + return count + +print(steps(2)) +print(steps(21)) +print(steps(52)) + +try: + result = steps(-2) + print(result) +except ValueError: + print("ValueError occured") + +try: + print(steps(0)) +except: + print("Except hit") + +print("Done") diff --git a/exercism.org/darts.py b/exercism.org/darts.py new file mode 100644 index 0000000..78f64a7 --- /dev/null +++ b/exercism.org/darts.py @@ -0,0 +1,12 @@ +""" Calculate points scored in a single toss of a Darts game """ + +def score(x, y): + """ Returns score as int depending on where the dart landed """ + target_radius = (x ** 2 + y ** 2) ** 0.5 + if target_radius <= 1: + return 10 + if target_radius <= 5: + return 5 + if target_radius <= 10: + return 1 + return 0 diff --git a/exercism.org/isbn-verifier.py b/exercism.org/isbn-verifier.py new file mode 100644 index 0000000..084f910 --- /dev/null +++ b/exercism.org/isbn-verifier.py @@ -0,0 +1,39 @@ +""" Module to check if a given isbn is a valid isbn10 code """ +def is_valid(isbn): + """ Returns 'True' or 'False' after checking isbn to be a valid isbn-10 code """ + isbn_to_check = isbn.replace("-", "") + + # check length a valid isbn has a length of 10 9 digits plus one check character + if not len(isbn_to_check) == 10: + return False + + # get check character + check_charakter = isbn_to_check[-1] + if check_charakter.lower() == "x": + check_charakter = 10 + elif not check_charakter.isnumeric(): + return False + + # check if position 0-9 are digits + if not isbn_to_check[:9].isnumeric(): + return False + + # check validity + multiplicator = 10 + checksum = 0 + + for number in isbn_to_check[:9]: + checksum += int(number) * multiplicator + multiplicator -= 1 + + checksum += int(check_charakter) + if checksum % 11 != 0: + return False + + return True + +print(is_valid("3-598-21508-8")) +print(is_valid(" 3-598-21508-8")) +print(is_valid("3-598-2108-8")) +print(is_valid("a-bdd-efghi-j")) +print(is_valid("3-598-21507-X")) \ No newline at end of file diff --git a/exercism.org/isogram.py b/exercism.org/isogram.py new file mode 100644 index 0000000..e4ba9cc --- /dev/null +++ b/exercism.org/isogram.py @@ -0,0 +1,26 @@ +""" Isogram checker """ +def is_isogram(string): + """ Checks if a given string is an isogram and returns 'True' or 'False' """ + letters = [] + string = string.lower() + + for letter in string: + if not letter.isalpha(): + continue + if letter not in letters: + letters.append(letter) + continue + return False + return True + +# testing function above +word1 = "lumberjack" +word2 = "isograms" +word3 = "six-year-old" +word4 = "Alphabet" + +words = [word1, word2, word3, word4] + +for word in words: + print(f"Is {word} an isogram?") + print(is_isogram(word)) diff --git a/exercism.org/line-up.py b/exercism.org/line-up.py new file mode 100644 index 0000000..33a440b --- /dev/null +++ b/exercism.org/line-up.py @@ -0,0 +1,20 @@ +""" Module to inform customers about their number in line of customers """ +def line_up(name, number): + """ Return a string telling customer rank in line """ + if number % 10 == 1 and not number % 100 == 11: + suffix = "st" + elif number % 10 == 2 and not number % 100 == 12: + suffix = "nd" + elif number % 10 == 3 and not number % 100 == 13: + suffix = "rd" + else: + suffix = "th" + + return f"{name}, you are the {number}{suffix} customer we serve today. Thank you!" + + +print(line_up("Mary", 1)) +print(line_up("John", 12)) +print(line_up("Dahir", 9)) + + diff --git a/exercism.org/little-sisters-vocab.py b/exercism.org/little-sisters-vocab.py new file mode 100644 index 0000000..ff11839 --- /dev/null +++ b/exercism.org/little-sisters-vocab.py @@ -0,0 +1,64 @@ +"""Functions for creating, transforming, and adding prefixes to strings.""" + + +def add_prefix_un(word): + """Take the given word and add the 'un' prefix. + + :param word: str - containing the root word. + :return: str - of root word prepended with 'un'. + """ + return "un" + word + + +def make_word_groups(vocab_words): + """Transform a list containing a prefix and words into a string with the prefix followed by the words with prefix prepended. + + :param vocab_words: list - of vocabulary words with prefix in first index. + :return: str - of prefix followed by vocabulary words with + prefix applied. + + This function takes a `vocab_words` list and returns a string + with the prefix and the words with prefix applied, separated + by ' :: '. + + For example: list('en', 'close', 'joy', 'lighten'), + produces the following string: 'en :: enclose :: enjoy :: enlighten'. + """ + separator = " :: " + vocab_words[0] + + return separator.join(vocab_words) + + +def remove_suffix_ness(word): + """Remove the suffix from the word while keeping spelling in mind. + + :param word: str - of word to remove suffix from. + :return: str - of word with suffix removed & spelling adjusted. + + For example: "heaviness" becomes "heavy", but "sadness" becomes "sad". + """ + if word[:-4].endswith("i"): + return word[:-5] + "y" + return word[:-4] + + +def adjective_to_verb(sentence, index): + """Change the adjective within the sentence to a verb. + + :param sentence: str - that uses the word in sentence. + :param index: int - index of the word to remove and transform. + :return: str - word that changes the extracted adjective to a verb. + + For example, ("It got dark as the sun set.", 2) becomes "darken". + """ + + words = sentence.split() + word = words[index] + if not word.isalpha(): + word = word[:-1] + return word + "en" + +print(adjective_to_verb("It got dark. as the sun set.", 2)) + +print(remove_suffix_ness("heaviness")) +print(remove_suffix_ness("sadness")) \ No newline at end of file diff --git a/exercism.org/meltdown-mitigation.py b/exercism.org/meltdown-mitigation.py new file mode 100644 index 0000000..abeca4c --- /dev/null +++ b/exercism.org/meltdown-mitigation.py @@ -0,0 +1,78 @@ +"""Functions to prevent a nuclear meltdown.""" + + +def is_criticality_balanced(temperature, neutrons_emitted): + """Verify criticality is balanced. + + :param temperature: int or float - temperature value in kelvin. + :param neutrons_emitted: int or float - number of neutrons emitted per second. + :return: bool - is criticality balanced? + + A reactor is said to be balanced in criticality if it satisfies the following conditions: + - The temperature is less than 800 K. + - The number of neutrons emitted per second is greater than 500. + - The product of temperature and neutrons emitted per second is less than 500000. + """ + + balanced_temp = temperature < 800 + balanced_neutrons = neutrons_emitted > 500 + balanced_product = temperature * neutrons_emitted < 500_000 + + return balanced_temp and balanced_neutrons and balanced_product + + +def reactor_efficiency(voltage, current, theoretical_max_power): + """Assess reactor efficiency zone. + + :param voltage: int or float - voltage value. + :param current: int or float - current value. + :param theoretical_max_power: int or float - power that corresponds to a 100% efficiency. + :return: str - one of ('green', 'orange', 'red', or 'black'). + + Efficiency can be grouped into 4 bands: + + 1. green -> efficiency of 80% or more, + 2. orange -> efficiency of less than 80% but at least 60%, + 3. red -> efficiency below 60%, but still 30% or more, + 4. black -> less than 30% efficient. + + The percentage value is calculated as + (generated power/ theoretical max power)*100 + where generated power = voltage * current + """ + + generated_power = voltage * current + + percentage = (generated_power / theoretical_max_power) * 100 + + if percentage >= 80: + return 'green' + if 80 > percentage >= 60: + return 'orange' + if 60 > percentage >= 30: + return 'red' + return 'black' + + +def fail_safe(temperature, neutrons_produced_per_second, threshold): + """Assess and return status code for the reactor. + + :param temperature: int or float - value of the temperature in kelvin. + :param neutrons_produced_per_second: int or float - neutron flux. + :param threshold: int or float - threshold for category. + :return: str - one of ('LOW', 'NORMAL', 'DANGER'). + + 1. 'LOW' -> `temperature * neutrons per second` < 90% of `threshold` + 2. 'NORMAL' -> `temperature * neutrons per second` +/- 10% of `threshold` + 3. 'DANGER' -> `temperature * neutrons per second` is not in the above-stated ranges + """ + + current_status = (temperature * neutrons_produced_per_second) + + if status < 90: + return 'LOW' + if threshold * 1.1 > status > threshold * 0.9: + return 'NORMAL' + else: + return 'DANGER' + diff --git a/exercism.org/perfect_number.py b/exercism.org/perfect_number.py new file mode 100644 index 0000000..2b9f1d2 --- /dev/null +++ b/exercism.org/perfect_number.py @@ -0,0 +1,27 @@ +""" Module to check numbers based on Nicomachus' classification """ + +def classify(number): + """ A perfect number equals the sum of its positive divisors. + + :param number: int a positive integer + :return: str the classification of the input integer + """ + if number <= 0: + raise ValueError("Classification is only possible for positive integers.") + + aliquot_sum = 0 + + for num in range(1, number): + if number % num == 0: + aliquot_sum += num + + if aliquot_sum > number: + return "abundant" + if aliquot_sum < number: + return "deficient" + return "perfect" + +print(classify(6)) +print(classify(12)) +print(classify(24)) +print(classify(8)) \ No newline at end of file diff --git a/exercism.org/pig-latin.py b/exercism.org/pig-latin.py new file mode 100644 index 0000000..95d7da4 --- /dev/null +++ b/exercism.org/pig-latin.py @@ -0,0 +1,103 @@ +""" +Rule 1 + +If a word begins with a vowel, or starts with "xr" or "yt", add an "ay" sound to the end of the word. + +For example: + + "apple" -> "appleay" (starts with vowel) + "xray" -> "xrayay" (starts with "xr") + "yttria" -> "yttriaay" (starts with "yt") + +Rule 2 + +If a word begins with one or more consonants, first move those consonants to the end of the word and then add an "ay" sound to the end of the word. + +For example: + + "pig" -> "igp" -> "igpay" (starts with single consonant) + "chair" -> "airch" -> "airchay" (starts with multiple consonants) + "thrush" -> "ushthr" -> "ushthray" (starts with multiple consonants) + +Rule 3 + +If a word starts with zero or more consonants followed by "qu", first move those consonants (if any) and the "qu" part to the end of the word, and then add an "ay" sound to the end of the word. + +For example: + + "quick" -> "ickqu" -> "ickquay" (starts with "qu", no preceding consonants) + "square" -> "aresqu" -> "aresquay" (starts with one consonant followed by "qu") + +Rule 4 + +If a word starts with one or more consonants followed by "y", first move the consonants preceding the "y"to the end of the word, and then add an "ay" sound to the end of the word. + +Some examples: + + "my" -> "ym" -> "ymay" (starts with single consonant followed by "y") + "rhythm" -> "ythmrh" -> "ythmrhay" (starts with multiple consonants followed by "y") + +""" + +""" Pig latin module """ +def translate(text): + """ Translate input to pig latin text """ + vowels = ("a", "e", "i", "o", "u") + rule1 = ("a", "e", "i", "o", "u", "xr", "yt") + + text_as_list = text.split(" ") + translated_words = [] + + for word in text_as_list: + translated_word = word + consonants = "" + + for char in translated_word: + if char in vowels: + break + consonants = consonants + char + + if word.startswith(rule1): + translated_words.append(word) + elif "qu" in word: + position_of_qu = word.find("qu") + if position_of_qu >= 2: + slice_of_word = word[:len(consonants)] + rest_of_word = word[len(consonants):] + if rest_of_word.startswith(vowels): + translated_word = rest_of_word + slice_of_word + translated_words.append(translated_word) + elif word.find("qu") >= 0: + translated_word = word[2 + position_of_qu:] + word[: 2 + position_of_qu] + translated_words.append(translated_word) + else: + if "y" in consonants: + position_of_y = consonants.find("y") + if position_of_y == 0: + translated_word = word[position_of_y + 1:] + word[:position_of_y + 1] + translated_words.append(translated_word) + continue + translated_word = word[position_of_y:] + word[:position_of_y] + translated_words.append(translated_word) + continue + + translated_word = word[len(consonants):] + consonants + translated_words.append(translated_word) + + result = "" + + for translation in translated_words: + result = result + " " + translation + "ay" + + return result.strip() + + +print(translate("apple")) +print(translate("queen")) +print(translate("square")) +print(translate("pig")) +print(translate("chair")) +print(translate("my")) +print(translate("rhythm")) +print(translate("liquid")) +print(translate("yellow")) \ No newline at end of file diff --git a/exercism.org/resistor_color.py b/exercism.org/resistor_color.py new file mode 100644 index 0000000..6d737ed --- /dev/null +++ b/exercism.org/resistor_color.py @@ -0,0 +1,28 @@ +""" Resistor en- and decoding of colours """ + +def color_code(color): + """ Return int for color given""" + if color in colors(): + return colors().index(color) + return None + +def colors(): + """ Colors definition """ + colors_list = [ + "black", + "brown", + "red", + "orange", + "yellow", + "green", + "blue", + "violet", + "grey", + "white" + ] + return colors_list + +print(colors()) +print(color_code("black")) +print(color_code("blue")) +print(color_code("pink")) \ No newline at end of file diff --git a/exercism.org/rotational_cypher.py b/exercism.org/rotational_cypher.py new file mode 100644 index 0000000..b598cb5 --- /dev/null +++ b/exercism.org/rotational_cypher.py @@ -0,0 +1,35 @@ +""" Module to cypher input text """ +import string + +def rotate(text, key): + """ Encrypt input text using rotational cypher """ + lower = string.ascii_lowercase + upper = string.ascii_uppercase + #print(f"len(lower) = {len(lower)}") + result = "" + + for letter in text: + if letter in lower: + index = lower.find(letter) + new_index = index + key + if new_index >= len(lower): + new_index -= 26 + elif new_index < 0: + new_index += 26 + result += lower[new_index] + elif letter in upper: + index = upper.find(letter) + new_index = index + key + if new_index >= len(upper): + new_index -= 26 + result += upper[new_index] + else: + result += letter + + return result + + +print(rotate("a", 1)) +print(rotate("z", 1)) +print(rotate("a", -1)) +print(rotate("Cool", 12)) diff --git a/exercism.org/string_methods.py b/exercism.org/string_methods.py new file mode 100644 index 0000000..b6764d6 --- /dev/null +++ b/exercism.org/string_methods.py @@ -0,0 +1,39 @@ +"""Functions to help edit essay homework using string manipulation.""" + + +def capitalize_title(title): + """Convert the first letter of each word in the title to uppercase if needed. + + :param title: str - title string that needs title casing. + :return: str - title string in title case (first letters capitalized). + """ + return title.title() + + +def check_sentence_ending(sentence): + """Check the ending of the sentence to verify that a period is present. + + :param sentence: str - a sentence to check. + :return: bool - return True if punctuated correctly with period, False otherwise. + """ + return sentence.endswith(".") + +def clean_up_spacing(sentence): + """Verify that there isn't any whitespace at the start and end of the sentence. + + :param sentence: str - a sentence to clean of leading and trailing space characters. + :return: str - a sentence that has been cleaned of leading and trailing space characters. + """ + return sentence.strip() + + +def replace_word_choice(sentence, old_word, new_word): + """Replace a word in the provided sentence with a new one. + + :param sentence: str - a sentence to replace words in. + :param old_word: str - word to replace. + :param new_word: str - replacement word. + :return: str - input sentence with new words in place of old words. + """ + return sentence.replace(old_word, new_word) + diff --git a/exercism.org/triangle.py b/exercism.org/triangle.py new file mode 100644 index 0000000..18f4a04 --- /dev/null +++ b/exercism.org/triangle.py @@ -0,0 +1,60 @@ +""" Triangle module """ +def equilateral(sides): + """ Check if a triangle is equilateral and returns 'True' or 'False' """ + if not sides_len_okay(sides): + return False + + side1, side2, side3 = sides + + if side1 == side2 == side3: + return True + + return False + +def isosceles(sides): + """ Check if a triangle is isosceles and returns 'True' or 'False' """ + if not sides_len_okay(sides): + return False + + if not is_triangle(sides): + return False + + side1, side2, side3 = sides + + if side1 == side2 or side1 == side3 or side2 == side3: + return True + return False + +def scalene(sides): + """ Check if a triangle is scalene and returns 'True' or 'False' """ + if not sides_len_okay(sides): + return False + + if not is_triangle(sides): + return False + + side1, side2, side3 = sides + + if side1 == side2 == side3: + return False + if side1 == side2 or side1 == side3 or side2 == side3: + return False + return True + +def sides_len_okay(sides): + """ Check input sides to be longer than '0' """ + return all(side > 0 for side in sides) # complex but shorter than for with if nested + +def is_triangle(sides): + """ Check if input can be a triangle """ + side1, side2, side3 = sides + + conditions_met = 0 + + if side1 + side2 >= side3: + conditions_met += 1 + if side2 + side3 >= side1: + conditions_met += 1 + if side1 + side3 >= side2: + conditions_met += 1 + return conditions_met == 3 \ No newline at end of file diff --git a/open-hpi/week-3/notebooks-week-3/.ipynb_checkpoints/AssignmentWeek3Part2-checkpoint.ipynb b/open-hpi/week-3/notebooks-week-3/.ipynb_checkpoints/AssignmentWeek3Part2-checkpoint.ipynb new file mode 100644 index 0000000..5b56a42 --- /dev/null +++ b/open-hpi/week-3/notebooks-week-3/.ipynb_checkpoints/AssignmentWeek3Part2-checkpoint.ipynb @@ -0,0 +1,159 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1adeca91-89f5-495f-8b76-948c131c9551", + "metadata": {}, + "source": [ + "# Ceasar cipher\n", + "It' allowed to handle all transform input to lower case only. Do not alter whitespace and special characters\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "8de83ff5-28c5-4470-83e7-16c4585c945e", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter the number of places to shift: 0\n", + "Please enter a senctence: Hi, my name is ...!\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The encrypted sentence is: hi, my name is ...!\n" + ] + } + ], + "source": [ + "\"\"\" Ceasar ciper assignment \"\"\"\n", + "def encrypt(message, shift):\n", + " \"\"\" Returns encrypted message where the letters are shifted 'shift' positions \"\"\"\n", + " message = message.lower()\n", + " alphabet = \"abcdefghijklmnopqrstuvwxyz\"\n", + "\n", + " result = \"\"\n", + " \n", + " for letter in message:\n", + " if letter in alphabet:\n", + " index = alphabet.find(letter)\n", + " new_index = index + shift\n", + " if new_index > 25:\n", + " new_index -= 26\n", + " elif new_index < 0:\n", + " new_index += 26\n", + " result = result + alphabet[new_index]\n", + " continue\n", + " result = result + letter\n", + "\n", + " return result\n", + "\n", + "number_to_shift = \"x\"\n", + "\n", + "while not number_to_shift.isdecimal():\n", + " number_to_shift = input(\"Please enter the number of places to shift: \")\n", + "\n", + "number = int(number_to_shift)\n", + "user_message = input(\"Please enter a senctence: \")\n", + "encrypted_message = encrypt(user_message, number)\n", + "print(\"The encrypted sentence is:\", encrypted_message)\n", + "\n", + " \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "55f6fc9f-1645-4639-b476-c05c826cf28e", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter the number of places to shift: 1\n", + "Please enter a senctence: z\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The encrypted sentence is: e\n" + ] + } + ], + "source": [ + "\"\"\" Ceasar ciper assignment \"\"\"\n", + "def encrypt(message, shift):\n", + " \"\"\" Returns encrypted message where the letters are shifted 'shift' positions \"\"\"\n", + " message = message.lower()\n", + " alphabet = \"abcdefghijklmnopqrstuvwxyz\"\n", + "\n", + " result = \"\"\n", + " \n", + " for letter in message:\n", + " if letter in alphabet:\n", + " index = alphabet.find(letter)\n", + " new_index = index + shift\n", + " if 0 > new_index or new_index > 25:\n", + " new_index = new_index % 25 \n", + " result = result + alphabet[new_index]\n", + " continue\n", + " result = result + letter\n", + "\n", + " return result\n", + "\n", + "while True:\n", + " number_to_shift = int(input(\"Please enter the number of places to shift: \"))\n", + "\n", + " if number_to_shift < 0 or number_to_shift > 25:\n", + " print(\"You need to enter a number between 0 and 25!\")\n", + " continue\n", + " break\n", + " \n", + "\n", + "user_message = input(\"Please enter a senctence: \")\n", + "encrypted_message = encrypt(user_message, number)\n", + "print(\"The encrypted sentence is:\", encrypted_message)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b8793a8-c1d5-4044-be62-f2648b134c3c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.13.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/open-hpi/week-3/notebooks-week-3/.ipynb_checkpoints/week_3_unit_6_while_notebook-checkpoint.ipynb b/open-hpi/week-3/notebooks-week-3/.ipynb_checkpoints/week_3_unit_6_while_notebook-checkpoint.ipynb new file mode 100644 index 0000000..fe52367 --- /dev/null +++ b/open-hpi/week-3/notebooks-week-3/.ipynb_checkpoints/week_3_unit_6_while_notebook-checkpoint.ipynb @@ -0,0 +1,644 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The [while](https://docs.python.org/3/reference/compound_stmts.html#while) loop\n", + "\n", + "You are already familiar with the `for` loop. There is another loop in Python, the\n", + "`while` loop. The `while` loop offers more flexibility, but can be a bit more\n", + "complex to use.\n", + "\n", + "The `for` loop works well when you have a sequence to iterate over, like a list or\n", + "a range. However, there are scenarios where you need to repeat an operation multiple\n", + "times without a predefined sequence:\n", + "- At an ATM, the system prompts for a PIN until it is entered correctly.\n", + "- A user must enter a value that can be converted into a number.\n", + "- A user should keep answering questions until none remain. In such cases, a `while`\n", + " loop is a better choice than using a `for` loop with \"tricks\".\n", + "\n", + "## Syntax of the `while` loop\n", + "\n", + "The simplest form of a `while` loop is structured as follows:\n", + "\n", + "```python\n", + "while condition:\n", + " statement1\n", + " statement2\n", + " ...\n", + " statementN\n", + "```\n", + "\n", + "The loop begins with the keyword `while`, followed by a condition and a colon, much\n", + "like an `if` statement. The subsequent block of code should be indented, similar to\n", + "other control structures. When the loop's indented code is done executing, the program\n", + "resumes execution with the non-indented code following the loop.\n", + "\n", + "## How a `while` loop works\n", + "\n", + "To start, the loop checks the condition specified after `while`. If the condition is\n", + "`True`, the loop's body is executed. Upon reaching the end of the loop body, the\n", + "program returns to the `while` condition and checks it again. \n", + "The loop continues running as long as the condition remains `True`. Once the condition\n", + "becomes `False`, the loop ends and the program continues with the code following the\n", + "loop. \n", + "If the condition is `False` the first time the `while` loop is encountered, the loop's\n", + "body is skipped entirely and the program continues immediately after the loop.\n", + "\n", + "## Example 1: Using `input()` until a number is entered\n", + "\n", + "Consider this problem: You need to enter a number using `input()`. For calculations,\n", + "the entered string must first be converted to a number, such as an integer using\n", + "`int()`. If the user enters non-numeric input, the conversion will cause an error.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter a number: a\n" + ] + }, + { + "ename": "ValueError", + "evalue": "invalid literal for int() with base 10: 'a'", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mValueError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 2\u001b[39m\n\u001b[32m 1\u001b[39m number = \u001b[38;5;28minput\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPlease enter a number: \u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m2\u001b[39m number = \u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mnumber\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[31mValueError\u001b[39m: invalid literal for int() with base 10: 'a'" + ] + } + ], + "source": [ + "number = input(\"Please enter a number: \")\n", + "number = int(number)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To avoid this, we can use a `while` loop. The loop's condition checks if the input is\n", + "numeric using the `.isdecimal()` method. Until a valid number is entered, the loop can\n", + "keep requesting input. Once a number is entered, conversion occurs **after** the loop." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter number: 15.55\n", + "Please enter number: 15,55\n", + "Please enter number: 12\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "12\n" + ] + } + ], + "source": [ + "# The loop runs until a suitable input is available\n", + "number = \"x\"\n", + "while not (number.isdecimal()):\n", + " number = input(\"Please enter number: \")\n", + "\n", + "number = int(number)\n", + "print(number)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An *imperfection* in the loop is visible above: To check the condition initially, the\n", + "variable `number` must be declared first but with a value that is not a number.\n", + "Setting `number = \"x\"` is solely to initialize it with something besides an integer.\n", + "\n", + "Alternatively, this variant is possible:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter number: 15,2\n", + "Please enter number: 45\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "45\n" + ] + } + ], + "source": [ + "# The loop runs until a suitable input is available\n", + "number = input(\"Please enter number: \")\n", + "while not (number.isdecimal()):\n", + " number = input(\"Please enter number: \")\n", + "\n", + "number = int(number)\n", + "print(number)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Although the statement in line two is less \"meaningless,\" there is now a\n", + "duplicated `input` statements. This is not the most elegant programming style. \n", + "Question: Why can the `int(number)` conversion occur only after the loop?\n", + "\n", + "## Example 2: Check PIN\n", + "\n", + "In this example, we have a secret PIN. The user must enter the correct PIN to proceed\n", + "beyond the `while` loop. The program structure is similar to the previous example.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "secret_pin = 1234\n", + "\n", + "pin = int(input(\"Please enter PIN: \"))\n", + "\n", + "while pin != secret_pin:\n", + " print(\"The PIN was wrong.\")\n", + " pin = int(input(\"Please enter PIN: \"))\n", + "\n", + "print(pin, \"is correct\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In real life, attempts at entering a PIN are usually limited. ATMs typically allow \n", + "only three tries before blocking. How can we represent this in our loop?\n", + "\n", + "We need a condition that checks both if the PIN is correct and if attempts exceed \n", + "three. Here's how this can be implemented:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "secret_pin = 1234\n", + "\n", + "pin = int(input(\"Please enter PIN: \"))\n", + "attempts = 1\n", + "\n", + "while (pin != secret_pin) and (attempts < 3):\n", + " print(\"The PIN was wrong.\")\n", + " pin = int(input(\"Please enter PIN: \"))\n", + " attempts += 1\n", + "\n", + "if pin == secret_pin:\n", + " print(pin, \"is correct\")\n", + "else:\n", + " print(\"You entered the wrong PIN three times, your card will be confiscated.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This program also has *imperfections*. A second variable `attempts` is required, \n", + "initialized before the loop and incremented inside it. After the loop, it's not \n", + "directly clear why it ended — was it a correct PIN or exceeded attempts? An `if` \n", + "statement is needed to clarify this." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 3: Simple counter\n", + "\n", + "In the previous example, a counter (`attempts`) was used, illustrating the basic act \n", + "of incrementing variables. Here's how you can count from 1 to 10 with a `while` loop:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n", + "6\n", + "7\n", + "8\n", + "9\n", + "10\n" + ] + } + ], + "source": [ + "# Simple counter\n", + "# The following program is to count from 1 - 10\n", + "i = 1\n", + "while i <= 10:\n", + " print(i)\n", + " i += 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This solution appears straightforward. However, subtle details can \n", + "alter program behavior:\n", + "- Should `i` start at 1 or 0?\n", + "- Should the condition be `i <= 10` or `i < 10`?\n", + "- Should the comparison value be 10 or 11?\n", + "- Should the increment (`i += 1`) occur before or after `print()` in the loop body?\n", + "\n", + "Each small variation changes how the program behaves. Therefore, when applying `while`\n", + "loops, pay attention to boundary conditions. Experiment by modifying the above program\n", + "with these questions in mind and predict its output.\n", + "\n", + "## A Classic error: The infinite loop\n", + "\n", + "A common mistake is an infinite loop: a loop that never stops because its condition \n", + "always remains `True`. For instance, in the previous example, if the increment is \n", + "forgotten, the loop becomes infinite. \n", + "Note: To halt an infinite loop, press the Stop button at the top.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The following program is to count from 1 - 10\n", + "i = 1\n", + "while i <= 10:\n", + " print(i)\n", + " # Because of the commented out (forgotten) increment, the loop runs endlessly.\n", + " # i += 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using a `for` loop is simpler and more robust as it automatically checks boundaries. \n", + "Use a `for` loop when possible; it is simpler and thus reduces potential errors.\n", + "\n", + "# Example 4: Guessing a random number\n", + "\n", + "A `while` loop is well-suited for implementing a number guessing game.\n", + "In this game, a random number between 1 and 100 is generated. Unlike the previous PIN example, the secret number \n", + "is unknown to the user. After each guess, the program provides a hint indicating whether the secret number is higher \n", + "or lower than the user's guess. This process continues until the user correctly guesses the number.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 50\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 50 was too small.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 99\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 99 was too big.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 75\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 75 was too small.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 85\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 85 was too small.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 95\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 95 was too small.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 98\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 98 was too big.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 97\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Correct! 97 was the number you were looking for.\n" + ] + } + ], + "source": [ + "import random\n", + "\n", + "secret_number = random.randint(1, 100)\n", + "\n", + "guessed_number = int(input(\"Please guess a number: \"))\n", + "\n", + "while guessed_number != secret_number:\n", + " if guessed_number < secret_number:\n", + " print(\"The number\", guessed_number, \"was too small.\")\n", + " else:\n", + " print(\"The number\", guessed_number, \"was too big.\")\n", + "\n", + " guessed_number = int(input(\"Please guess a number: \"))\n", + "\n", + "print(\"Correct!\", guessed_number, \"was the number you were looking for.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exiting the loop with a `break`\n", + "\n", + "A while loop can be exited early using the break statement. When break is executed, the loop stops immediately — even if the loop condition is still true. After a break, the condition is no longer checked. Therefore, break is typically used inside an if statement within the loop.\n", + "\n", + "Using break can simplify certain programming tasks. For example, suppose we want to enter data for multiple students, where each student has a matriculation number, last name, and first name. Since we don’t know in advance how many students will be entered, a while loop is a good choice.\n", + "\n", + "We want the loop to stop when the user presses the return key without entering a matriculation number. This can be implemented cleanly using break, as shown below:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Enter matriculation number: 1122\n", + "Enter name: Levy\n", + "Enter first name: Joe\n", + "Enter matriculation number: 1133\n", + "Enter name: Sixpack\n", + "Enter first name: Jessica\n", + "Enter matriculation number: \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('1122', 'Levy', 'Joe'), ('1133', 'Sixpack', 'Jessica')]\n" + ] + } + ], + "source": [ + "list_of_students = []\n", + "\n", + "while True:\n", + " matnr = input(\"Enter matriculation number: \")\n", + " if matnr == \"\":\n", + " break\n", + " name = input(\"Enter name: \")\n", + " firstname = input(\"Enter first name: \")\n", + " list_of_students.append((matnr, name, firstname))\n", + "\n", + "print(list_of_students)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`while True:` sets up an infinite loop since `True` is always true. The loop only exits \n", + "via `break`. After the first `input()`, a condition checks whether to exit. If so, \n", + "the `break` ends the loop and prevents further `input()` calls." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise: Calculating value growth\n", + "\n", + "The value of a property increases by *p* percent every year. Write a program that calculates the value of the property\n", + "for each year until the value has doubled. Use `input()` to ask for the percentage and the initial value. \n", + "\n", + "Example input:\n", + "```\n", + "What is the property's value? 10000 \n", + "By what percentage does it increase yearly? 5\n", + "```\n", + "\n", + "Example output:\n", + "```\n", + "Year 0 - 10000.0 \n", + "Year 1 - 10500.0 \n", + "Year 2 - 11025.0\n", + "Year 3 - 11576.25\n", + "...\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "What is the property's value? 950\n", + "By what percentage does it increase yearly? 2\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Year 0 - 950.00\n", + "Year 1 - 969.00\n", + "Year 2 - 988.38\n", + "Year 3 - 1008.15\n", + "Year 4 - 1028.31\n", + "Year 5 - 1048.88\n", + "Year 6 - 1069.85\n", + "Year 7 - 1091.25\n", + "Year 8 - 1113.08\n", + "Year 9 - 1135.34\n", + "Year 10 - 1158.04\n", + "Year 11 - 1181.21\n", + "Year 12 - 1204.83\n", + "Year 13 - 1228.93\n", + "Year 14 - 1253.50\n", + "Year 15 - 1278.57\n", + "Year 16 - 1304.15\n", + "Year 17 - 1330.23\n", + "Year 18 - 1356.83\n", + "Year 19 - 1383.97\n", + "Year 20 - 1411.65\n", + "Year 21 - 1439.88\n", + "Year 22 - 1468.68\n", + "Year 23 - 1498.05\n", + "Year 24 - 1528.02\n", + "Year 25 - 1558.58\n", + "Year 26 - 1589.75\n", + "Year 27 - 1621.54\n", + "Year 28 - 1653.97\n", + "Year 29 - 1687.05\n", + "Year 30 - 1720.79\n", + "Year 31 - 1755.21\n", + "Year 32 - 1790.31\n", + "Year 33 - 1826.12\n", + "Year 34 - 1862.64\n", + "Year 35 - 1899.90\n" + ] + } + ], + "source": [ + "property_value = int(input(\"What is the property's value? \"))\n", + "percentage = float(input(\"By what percentage does it increase yearly? \"))\n", + "\n", + "current_value = property_value\n", + "year = 0\n", + "\n", + "while current_value <= property_value * 2:\n", + " print(f\"Year {year} - {current_value:.2f}\")\n", + " #current_value = current_value + (current_value * percentage / 100)\n", + " current_value = current_value * (1 + percentage/100)\n", + " year += 1 " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.13.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/open-hpi/week-3/notebooks-week-3/AssignmentWeek3Part2.ipynb b/open-hpi/week-3/notebooks-week-3/AssignmentWeek3Part2.ipynb new file mode 100644 index 0000000..5b56a42 --- /dev/null +++ b/open-hpi/week-3/notebooks-week-3/AssignmentWeek3Part2.ipynb @@ -0,0 +1,159 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "1adeca91-89f5-495f-8b76-948c131c9551", + "metadata": {}, + "source": [ + "# Ceasar cipher\n", + "It' allowed to handle all transform input to lower case only. Do not alter whitespace and special characters\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "8de83ff5-28c5-4470-83e7-16c4585c945e", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter the number of places to shift: 0\n", + "Please enter a senctence: Hi, my name is ...!\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The encrypted sentence is: hi, my name is ...!\n" + ] + } + ], + "source": [ + "\"\"\" Ceasar ciper assignment \"\"\"\n", + "def encrypt(message, shift):\n", + " \"\"\" Returns encrypted message where the letters are shifted 'shift' positions \"\"\"\n", + " message = message.lower()\n", + " alphabet = \"abcdefghijklmnopqrstuvwxyz\"\n", + "\n", + " result = \"\"\n", + " \n", + " for letter in message:\n", + " if letter in alphabet:\n", + " index = alphabet.find(letter)\n", + " new_index = index + shift\n", + " if new_index > 25:\n", + " new_index -= 26\n", + " elif new_index < 0:\n", + " new_index += 26\n", + " result = result + alphabet[new_index]\n", + " continue\n", + " result = result + letter\n", + "\n", + " return result\n", + "\n", + "number_to_shift = \"x\"\n", + "\n", + "while not number_to_shift.isdecimal():\n", + " number_to_shift = input(\"Please enter the number of places to shift: \")\n", + "\n", + "number = int(number_to_shift)\n", + "user_message = input(\"Please enter a senctence: \")\n", + "encrypted_message = encrypt(user_message, number)\n", + "print(\"The encrypted sentence is:\", encrypted_message)\n", + "\n", + " \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "55f6fc9f-1645-4639-b476-c05c826cf28e", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter the number of places to shift: 1\n", + "Please enter a senctence: z\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The encrypted sentence is: e\n" + ] + } + ], + "source": [ + "\"\"\" Ceasar ciper assignment \"\"\"\n", + "def encrypt(message, shift):\n", + " \"\"\" Returns encrypted message where the letters are shifted 'shift' positions \"\"\"\n", + " message = message.lower()\n", + " alphabet = \"abcdefghijklmnopqrstuvwxyz\"\n", + "\n", + " result = \"\"\n", + " \n", + " for letter in message:\n", + " if letter in alphabet:\n", + " index = alphabet.find(letter)\n", + " new_index = index + shift\n", + " if 0 > new_index or new_index > 25:\n", + " new_index = new_index % 25 \n", + " result = result + alphabet[new_index]\n", + " continue\n", + " result = result + letter\n", + "\n", + " return result\n", + "\n", + "while True:\n", + " number_to_shift = int(input(\"Please enter the number of places to shift: \"))\n", + "\n", + " if number_to_shift < 0 or number_to_shift > 25:\n", + " print(\"You need to enter a number between 0 and 25!\")\n", + " continue\n", + " break\n", + " \n", + "\n", + "user_message = input(\"Please enter a senctence: \")\n", + "encrypted_message = encrypt(user_message, number)\n", + "print(\"The encrypted sentence is:\", encrypted_message)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b8793a8-c1d5-4044-be62-f2648b134c3c", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.13.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/open-hpi/week-3/notebooks-week-3/week_3_unit_4_safedict_notebook.ipynb b/open-hpi/week-3/notebooks-week-3/week_3_unit_4_safedict_notebook.ipynb new file mode 100644 index 0000000..4647a5c --- /dev/null +++ b/open-hpi/week-3/notebooks-week-3/week_3_unit_4_safedict_notebook.ipynb @@ -0,0 +1,189 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Safe dictionary access\n", + "\n", + "When you try to access a key that does not exist in a dictionary, you will\n", + "encounter a `KeyError`. This is demonstrated in the following example:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Peter\n" + ] + }, + { + "ename": "KeyError", + "evalue": "3456", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mKeyError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28mdict\u001b[39m = {\u001b[32m1234\u001b[39m: \u001b[33m\"\u001b[39m\u001b[33mPeter\u001b[39m\u001b[33m\"\u001b[39m, \u001b[32m2345\u001b[39m: \u001b[33m\"\u001b[39m\u001b[33mJane\u001b[39m\u001b[33m\"\u001b[39m}\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mdict\u001b[39m[\u001b[32m1234\u001b[39m])\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28;43mdict\u001b[39;49m\u001b[43m[\u001b[49m\u001b[32;43m3456\u001b[39;49m\u001b[43m]\u001b[49m)\n", + "\u001b[31mKeyError\u001b[39m: 3456" + ] + } + ], + "source": [ + "dict = {1234: \"Peter\", 2345: \"Jane\"}\n", + "print(dict[1234])\n", + "print(dict[3456])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Safe access to a dictionary using `in`\n", + "\n", + "To prevent your program from being interrupted by errors, it is a good idea to\n", + "catch these potential errors. Using the keyword `in`, you can check if a key\n", + "exists in the dictionary, and thus avoid the error entirely. The expression\n", + "`key in dict` will return `True` if the key exists in the dictionary, and\n", + "`False` otherwise. You can use this within an `if` statement to handle the\n", + "situation gracefully." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter matriculation number: 488962\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The student you are looking for is: ('Abbott', 'Hannah', 'hannah@hogwarts.wiz', 'Apparition')\n" + ] + } + ], + "source": [ + "dict_of_students = {\n", + " 477264: (\"Potter\", \"Harry\", \"harry@hogwarts.wiz\", \"Defence Against the Dark Arts\"),\n", + " 490134: (\"Weasley\", \"Ron\", \"ron@hogwarts.wiz\", \"Care of Magical Creatures\"),\n", + " 471617: (\"Granger\", \"Hermione\", \"hermione@hogwarts.wiz\", \"Alchemy\"),\n", + " 432646: (\"Creevey\", \"Colin\", \"colin@hogwarts.wiz\", \"Music\"),\n", + " 481989: (\"Finnigan\", \"Seamus\", \"seamus@hogwarts.wiz\", \"Ancient Studies\"),\n", + " 488962: (\"Abbott\", \"Hannah\", \"hannah@hogwarts.wiz\", \"Apparition\"),\n", + " 482103: (\"Parkinson\", \"Pansy\", \"pansy@hogwarts.wiz\", \"Dark Arts\"),\n", + " 492010: (\"Malfoy\", \"Draco\", \"draco@hogwarts.wiz\", \"Defence Against the Dark Arts\"),\n", + " 447924: (\"Thomas\", \"Dean\", \"dean.thomas@hogwarts.wiz\", \"Divination\"),\n", + "}\n", + "\n", + "matrnr = int(input(\"Please enter matriculation number: \"))\n", + "if matrnr in dict_of_students:\n", + " print(\"The student you are looking for is:\", dict_of_students[matrnr])\n", + "else:\n", + " print(\"A student with this matriculation number does not exist\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Alternative: Using [dict.get()](https://docs.python.org/3/library/stdtypes.html#dict.get) to access values safely\n", + "\n", + "Another way to avoid errors is by using the `get()` method to retrieve the\n", + "value associated with a given key. This method can take two arguments:\n", + "\n", + "`dict.get(key, default)`\n", + "\n", + "The first argument is the `key` you want to retrieve the value for (such as the\n", + "matriculation number in the above example). The second, **optional** argument,\n", + "`default`, specifies the return value if the `key` is not found in the\n", + "dictionary. If you do not provide the `default` argument, the method will \n", + "return `None` by default, and no error will be raised, so your program will \n", + "continue to run smoothly. Below is an example of how to implement this \n", + "technique:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter matriculation number: 45687\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "For the matriculation number 45687 the dictionary returned the following result: no matching student found for this matriculation number\n" + ] + } + ], + "source": [ + "input_num = int(input(\"Please enter matriculation number:\"))\n", + "student = dict_of_students.get(\n", + " input_num, \"no matching student found for this matriculation number\"\n", + ")\n", + "\n", + "print(\n", + " \"For the matriculation number\",\n", + " input_num,\n", + " \"the dictionary returned the following result:\",\n", + " student,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "file_extension": ".py", + "interpreter": { + "hash": "ac59ebe37160ed0dfa835113d9b8498d9f09ceb179beaac4002f036b9467c963" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.13.12" + }, + "mimetype": "text/x-python", + "name": "python", + "npconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": 3 + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/open-hpi/week-3/notebooks-week-3/week_3_unit_5_impfunct_notebook.ipynb b/open-hpi/week-3/notebooks-week-3/week_3_unit_5_impfunct_notebook.ipynb new file mode 100644 index 0000000..925674d --- /dev/null +++ b/open-hpi/week-3/notebooks-week-3/week_3_unit_5_impfunct_notebook.ipynb @@ -0,0 +1,131 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Important functions and methods for complex data types\n", + "\n", + "This unit serves as a recap to summarize the key functions and methods for \n", + "[Lists](https://docs.python.org/3/library/stdtypes.html#lists), \n", + "[Tuples](https://docs.python.org/3/library/stdtypes.html#tuples), and \n", + "[Dictionaries](https://docs.python.org/3/library/stdtypes.html#mapping-types-dict).\n", + "\n", + "The tables below provide an overview of various methods and functions, along with \n", + "an indication of whether they are applicable to the data types mentioned above:\n", + "\n", + "| **Method** | **Description** | **List** | **Tuple** | **Dictionary** |\n", + "| :----------------- | :---------------------------------------- | :------: | :-------: | :------------: |\n", + "| `.sort()` | Sorts the object | X | | |\n", + "| `.append(x)` | Appends *x* to the end of the object | X | | |\n", + "| `.pop(i)` | Removes item at index *i* from the object | X | | X |\n", + "| `.insert(i, x)` | Inserts *x* at index *i* | X | | |\n", + "| `.remove(x)` | Removes the first occurrence of *x* | X | | |\n", + "| `.count(x)` | Counts the number of occurrences of *x* | X | X | |\n", + "| `.index(x)` | Returns the index of *x* | X | X | |\n", + "| `.keys()` | Returns all `keys` of the dictionary | | | X |\n", + "| `.values()` | Returns all `values` of the dictionary | | | X |\n", + "| `.items()` | Returns all `items` of the dictionary | | | X |\n", + "\n", + "\n", + "\n", + "| **Function** | **Description** | **List** | **Tuple** | **Dictionary** |\n", + "| :----------------- | :---------------------------------------- | :------: | :-------: | :------------: |\n", + "| `del object[item]` | Deletes *item* from *object* | X | | X |\n", + "| `len(object)` | Returns the length of *object* | X | X | X |\n", + "| `min(object)` | Returns the smallest item in *object* | X | X | [1](#fn1) |\n", + "| `max(object)` | Returns the largest item in *object* | X | X | [1](#fn1) |\n", + "| `sorted(object)` | Returns a sorted list of the items in *object* | X | X | [1](#fn1) |\n", + "\n", + "It should be evident why the first five **methods** apply only to lists — they modify \n", + "the object, and since tuples are immutable, these methods are unavailable for them. \n", + "Regarding dictionaries, sorting is unnecessary because values are accessed using a \n", + "`key`, not an index. Inserting values into a dictionary uses different syntax, and \n", + "removing the first occurrence of a value doesn't make sense because dictionaries \n", + "can have any order, and items are accessed using keys. \n", + "The last set of **methods** is specific to dictionaries, as lists and tuples do not \n", + "have keys and values. Therefore, these methods work only for dictionaries.\n", + "\n", + "The `del` keyword operates only on mutable data types and not on tuples. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example\n", + "\n", + "The methods mentioned above can be used to identify which letter occurs most often \n", + "in a text. Note that this example is solely to demonstrate the use of these \n", + "methods. A dictionary would provide a more efficient solution." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[15, 2, 8, 11, 18, 0, 2, 0, 23, 0, 0, 10, 13, 12, 18, 4, 4, 9, 11, 15, 12, 1, 0, 2, 0, 0]\n", + "23\n", + "8\n", + "i\n" + ] + } + ], + "source": [ + "text = \"lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\"\n", + "letters = \"abcdefghijklmnopqrstuvwxyz\"\n", + "\n", + "result = []\n", + "for l in letters:\n", + " result.append(text.count(l))\n", + "\n", + "print(result)\n", + "\n", + "max_count = max(result)\n", + "print(max_count)\n", + "\n", + "max_index = result.index(max_count)\n", + "print(max_index)\n", + "print(letters[max_index])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Footnote\n", + "[1](#fn1-back) In general, the last three functions are also applicable to dictionaries. However, \n", + "it is more common to use these functions with the values or keys of a dictionary." + ] + } + ], + "metadata": { + "interpreter": { + "hash": "fb768b9b3ecf961ba38b0c7e836f7f85a23c08c1797458e7c652470f2ae90c9c" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.13.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/open-hpi/week-3/notebooks-week-3/week_3_unit_6_while_notebook.ipynb b/open-hpi/week-3/notebooks-week-3/week_3_unit_6_while_notebook.ipynb new file mode 100644 index 0000000..fe52367 --- /dev/null +++ b/open-hpi/week-3/notebooks-week-3/week_3_unit_6_while_notebook.ipynb @@ -0,0 +1,644 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The [while](https://docs.python.org/3/reference/compound_stmts.html#while) loop\n", + "\n", + "You are already familiar with the `for` loop. There is another loop in Python, the\n", + "`while` loop. The `while` loop offers more flexibility, but can be a bit more\n", + "complex to use.\n", + "\n", + "The `for` loop works well when you have a sequence to iterate over, like a list or\n", + "a range. However, there are scenarios where you need to repeat an operation multiple\n", + "times without a predefined sequence:\n", + "- At an ATM, the system prompts for a PIN until it is entered correctly.\n", + "- A user must enter a value that can be converted into a number.\n", + "- A user should keep answering questions until none remain. In such cases, a `while`\n", + " loop is a better choice than using a `for` loop with \"tricks\".\n", + "\n", + "## Syntax of the `while` loop\n", + "\n", + "The simplest form of a `while` loop is structured as follows:\n", + "\n", + "```python\n", + "while condition:\n", + " statement1\n", + " statement2\n", + " ...\n", + " statementN\n", + "```\n", + "\n", + "The loop begins with the keyword `while`, followed by a condition and a colon, much\n", + "like an `if` statement. The subsequent block of code should be indented, similar to\n", + "other control structures. When the loop's indented code is done executing, the program\n", + "resumes execution with the non-indented code following the loop.\n", + "\n", + "## How a `while` loop works\n", + "\n", + "To start, the loop checks the condition specified after `while`. If the condition is\n", + "`True`, the loop's body is executed. Upon reaching the end of the loop body, the\n", + "program returns to the `while` condition and checks it again. \n", + "The loop continues running as long as the condition remains `True`. Once the condition\n", + "becomes `False`, the loop ends and the program continues with the code following the\n", + "loop. \n", + "If the condition is `False` the first time the `while` loop is encountered, the loop's\n", + "body is skipped entirely and the program continues immediately after the loop.\n", + "\n", + "## Example 1: Using `input()` until a number is entered\n", + "\n", + "Consider this problem: You need to enter a number using `input()`. For calculations,\n", + "the entered string must first be converted to a number, such as an integer using\n", + "`int()`. If the user enters non-numeric input, the conversion will cause an error.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter a number: a\n" + ] + }, + { + "ename": "ValueError", + "evalue": "invalid literal for int() with base 10: 'a'", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mValueError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 2\u001b[39m\n\u001b[32m 1\u001b[39m number = \u001b[38;5;28minput\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33mPlease enter a number: \u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m----> \u001b[39m\u001b[32m2\u001b[39m number = \u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mnumber\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[31mValueError\u001b[39m: invalid literal for int() with base 10: 'a'" + ] + } + ], + "source": [ + "number = input(\"Please enter a number: \")\n", + "number = int(number)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To avoid this, we can use a `while` loop. The loop's condition checks if the input is\n", + "numeric using the `.isdecimal()` method. Until a valid number is entered, the loop can\n", + "keep requesting input. Once a number is entered, conversion occurs **after** the loop." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter number: 15.55\n", + "Please enter number: 15,55\n", + "Please enter number: 12\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "12\n" + ] + } + ], + "source": [ + "# The loop runs until a suitable input is available\n", + "number = \"x\"\n", + "while not (number.isdecimal()):\n", + " number = input(\"Please enter number: \")\n", + "\n", + "number = int(number)\n", + "print(number)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An *imperfection* in the loop is visible above: To check the condition initially, the\n", + "variable `number` must be declared first but with a value that is not a number.\n", + "Setting `number = \"x\"` is solely to initialize it with something besides an integer.\n", + "\n", + "Alternatively, this variant is possible:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please enter number: 15,2\n", + "Please enter number: 45\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "45\n" + ] + } + ], + "source": [ + "# The loop runs until a suitable input is available\n", + "number = input(\"Please enter number: \")\n", + "while not (number.isdecimal()):\n", + " number = input(\"Please enter number: \")\n", + "\n", + "number = int(number)\n", + "print(number)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Although the statement in line two is less \"meaningless,\" there is now a\n", + "duplicated `input` statements. This is not the most elegant programming style. \n", + "Question: Why can the `int(number)` conversion occur only after the loop?\n", + "\n", + "## Example 2: Check PIN\n", + "\n", + "In this example, we have a secret PIN. The user must enter the correct PIN to proceed\n", + "beyond the `while` loop. The program structure is similar to the previous example.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "secret_pin = 1234\n", + "\n", + "pin = int(input(\"Please enter PIN: \"))\n", + "\n", + "while pin != secret_pin:\n", + " print(\"The PIN was wrong.\")\n", + " pin = int(input(\"Please enter PIN: \"))\n", + "\n", + "print(pin, \"is correct\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In real life, attempts at entering a PIN are usually limited. ATMs typically allow \n", + "only three tries before blocking. How can we represent this in our loop?\n", + "\n", + "We need a condition that checks both if the PIN is correct and if attempts exceed \n", + "three. Here's how this can be implemented:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "secret_pin = 1234\n", + "\n", + "pin = int(input(\"Please enter PIN: \"))\n", + "attempts = 1\n", + "\n", + "while (pin != secret_pin) and (attempts < 3):\n", + " print(\"The PIN was wrong.\")\n", + " pin = int(input(\"Please enter PIN: \"))\n", + " attempts += 1\n", + "\n", + "if pin == secret_pin:\n", + " print(pin, \"is correct\")\n", + "else:\n", + " print(\"You entered the wrong PIN three times, your card will be confiscated.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This program also has *imperfections*. A second variable `attempts` is required, \n", + "initialized before the loop and incremented inside it. After the loop, it's not \n", + "directly clear why it ended — was it a correct PIN or exceeded attempts? An `if` \n", + "statement is needed to clarify this." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 3: Simple counter\n", + "\n", + "In the previous example, a counter (`attempts`) was used, illustrating the basic act \n", + "of incrementing variables. Here's how you can count from 1 to 10 with a `while` loop:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n", + "6\n", + "7\n", + "8\n", + "9\n", + "10\n" + ] + } + ], + "source": [ + "# Simple counter\n", + "# The following program is to count from 1 - 10\n", + "i = 1\n", + "while i <= 10:\n", + " print(i)\n", + " i += 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This solution appears straightforward. However, subtle details can \n", + "alter program behavior:\n", + "- Should `i` start at 1 or 0?\n", + "- Should the condition be `i <= 10` or `i < 10`?\n", + "- Should the comparison value be 10 or 11?\n", + "- Should the increment (`i += 1`) occur before or after `print()` in the loop body?\n", + "\n", + "Each small variation changes how the program behaves. Therefore, when applying `while`\n", + "loops, pay attention to boundary conditions. Experiment by modifying the above program\n", + "with these questions in mind and predict its output.\n", + "\n", + "## A Classic error: The infinite loop\n", + "\n", + "A common mistake is an infinite loop: a loop that never stops because its condition \n", + "always remains `True`. For instance, in the previous example, if the increment is \n", + "forgotten, the loop becomes infinite. \n", + "Note: To halt an infinite loop, press the Stop button at the top.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The following program is to count from 1 - 10\n", + "i = 1\n", + "while i <= 10:\n", + " print(i)\n", + " # Because of the commented out (forgotten) increment, the loop runs endlessly.\n", + " # i += 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using a `for` loop is simpler and more robust as it automatically checks boundaries. \n", + "Use a `for` loop when possible; it is simpler and thus reduces potential errors.\n", + "\n", + "# Example 4: Guessing a random number\n", + "\n", + "A `while` loop is well-suited for implementing a number guessing game.\n", + "In this game, a random number between 1 and 100 is generated. Unlike the previous PIN example, the secret number \n", + "is unknown to the user. After each guess, the program provides a hint indicating whether the secret number is higher \n", + "or lower than the user's guess. This process continues until the user correctly guesses the number.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 50\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 50 was too small.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 99\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 99 was too big.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 75\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 75 was too small.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 85\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 85 was too small.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 95\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 95 was too small.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 98\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number 98 was too big.\n" + ] + }, + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Please guess a number: 97\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Correct! 97 was the number you were looking for.\n" + ] + } + ], + "source": [ + "import random\n", + "\n", + "secret_number = random.randint(1, 100)\n", + "\n", + "guessed_number = int(input(\"Please guess a number: \"))\n", + "\n", + "while guessed_number != secret_number:\n", + " if guessed_number < secret_number:\n", + " print(\"The number\", guessed_number, \"was too small.\")\n", + " else:\n", + " print(\"The number\", guessed_number, \"was too big.\")\n", + "\n", + " guessed_number = int(input(\"Please guess a number: \"))\n", + "\n", + "print(\"Correct!\", guessed_number, \"was the number you were looking for.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exiting the loop with a `break`\n", + "\n", + "A while loop can be exited early using the break statement. When break is executed, the loop stops immediately — even if the loop condition is still true. After a break, the condition is no longer checked. Therefore, break is typically used inside an if statement within the loop.\n", + "\n", + "Using break can simplify certain programming tasks. For example, suppose we want to enter data for multiple students, where each student has a matriculation number, last name, and first name. Since we don’t know in advance how many students will be entered, a while loop is a good choice.\n", + "\n", + "We want the loop to stop when the user presses the return key without entering a matriculation number. This can be implemented cleanly using break, as shown below:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Enter matriculation number: 1122\n", + "Enter name: Levy\n", + "Enter first name: Joe\n", + "Enter matriculation number: 1133\n", + "Enter name: Sixpack\n", + "Enter first name: Jessica\n", + "Enter matriculation number: \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('1122', 'Levy', 'Joe'), ('1133', 'Sixpack', 'Jessica')]\n" + ] + } + ], + "source": [ + "list_of_students = []\n", + "\n", + "while True:\n", + " matnr = input(\"Enter matriculation number: \")\n", + " if matnr == \"\":\n", + " break\n", + " name = input(\"Enter name: \")\n", + " firstname = input(\"Enter first name: \")\n", + " list_of_students.append((matnr, name, firstname))\n", + "\n", + "print(list_of_students)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`while True:` sets up an infinite loop since `True` is always true. The loop only exits \n", + "via `break`. After the first `input()`, a condition checks whether to exit. If so, \n", + "the `break` ends the loop and prevents further `input()` calls." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercise: Calculating value growth\n", + "\n", + "The value of a property increases by *p* percent every year. Write a program that calculates the value of the property\n", + "for each year until the value has doubled. Use `input()` to ask for the percentage and the initial value. \n", + "\n", + "Example input:\n", + "```\n", + "What is the property's value? 10000 \n", + "By what percentage does it increase yearly? 5\n", + "```\n", + "\n", + "Example output:\n", + "```\n", + "Year 0 - 10000.0 \n", + "Year 1 - 10500.0 \n", + "Year 2 - 11025.0\n", + "Year 3 - 11576.25\n", + "...\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "What is the property's value? 950\n", + "By what percentage does it increase yearly? 2\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Year 0 - 950.00\n", + "Year 1 - 969.00\n", + "Year 2 - 988.38\n", + "Year 3 - 1008.15\n", + "Year 4 - 1028.31\n", + "Year 5 - 1048.88\n", + "Year 6 - 1069.85\n", + "Year 7 - 1091.25\n", + "Year 8 - 1113.08\n", + "Year 9 - 1135.34\n", + "Year 10 - 1158.04\n", + "Year 11 - 1181.21\n", + "Year 12 - 1204.83\n", + "Year 13 - 1228.93\n", + "Year 14 - 1253.50\n", + "Year 15 - 1278.57\n", + "Year 16 - 1304.15\n", + "Year 17 - 1330.23\n", + "Year 18 - 1356.83\n", + "Year 19 - 1383.97\n", + "Year 20 - 1411.65\n", + "Year 21 - 1439.88\n", + "Year 22 - 1468.68\n", + "Year 23 - 1498.05\n", + "Year 24 - 1528.02\n", + "Year 25 - 1558.58\n", + "Year 26 - 1589.75\n", + "Year 27 - 1621.54\n", + "Year 28 - 1653.97\n", + "Year 29 - 1687.05\n", + "Year 30 - 1720.79\n", + "Year 31 - 1755.21\n", + "Year 32 - 1790.31\n", + "Year 33 - 1826.12\n", + "Year 34 - 1862.64\n", + "Year 35 - 1899.90\n" + ] + } + ], + "source": [ + "property_value = int(input(\"What is the property's value? \"))\n", + "percentage = float(input(\"By what percentage does it increase yearly? \"))\n", + "\n", + "current_value = property_value\n", + "year = 0\n", + "\n", + "while current_value <= property_value * 2:\n", + " print(f\"Year {year} - {current_value:.2f}\")\n", + " #current_value = current_value + (current_value * percentage / 100)\n", + " current_value = current_value * (1 + percentage/100)\n", + " year += 1 " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.13.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/scopes-in-pyhton.py b/scopes-in-pyhton.py new file mode 100644 index 0000000..b471169 --- /dev/null +++ b/scopes-in-pyhton.py @@ -0,0 +1,42 @@ +x = "Hello, World" + +def func(): + x = 2 + print(f"Inside 'func', x has the value {x}") + +func() +print(f"Outside 'func', x has the value {x}") + + +# example of nested function explaining the scope of variables + +x = 5 + +def outer_func(): + y = 3 + + def inner_func(): + z = x + y + return z + + return inner_func() + +print(outer_func()) + +# global keyword + +total = 0 + +def add_to_total(n): + # without global total, total = ... would create a new assignment + # cannot access a new assigned variable in assignment + # global tells Python to look in the global scope for the name total + # using global is considered bad form in general + global total + total = total + n + +add_to_total(5) +print(total) + + +