<jupyter_start><jupyter_text>Decision makingYou control what your program does by making decisions, which often involves making comparisons. We use operators to make comparisons. These are often referred to as relational operators or comparison operators because by comparing items the algorithm is determining how two items are related.  Relational operatorsHere are the most common relational operators |Operator | Description ||---------|-------------|| == | Both are true|| != | Is not equal to|| < | Is less than || > | Is greater than || <= | Is less than or equal to || >= | Is greater than or equal to | Python also offers three logical operators, also called Boolean operators that can allow you assess multiple comparisons before making a final decision. Those operators use the English word for what they mean, as shown here. |Operator | Description ||---------|-------------|| and | Both are true|| or | One or the other is true|| not | Is not true |  Using the IF statementThe word if is used a lot in all apps and computer programs to make decisions. Thesimplest syntax for if is:>`if condition: >    do this>do this no matter what` The first `do this` line is executed only if the condition is **true**. If the conditionis **false**, the first `do this` command is ignored. Regardless of what the condition turns out to be, the second line is executed next. Notice that the `do this` is indented, and the `do this no matter what` is not. Thismeans a lot in Python, as you’ll see shortly. But first, let’s work through a few simpleexamples with this simple syntax. You can try it for yourself in a Jupyter notebookor file if you want to follow along. In the simple example below, the variable named `sun` receives thestring **down**. Then an `if` statement checks to see whether the variable **sun** containsthe word **down** and if it does, prints **Good night!**. Then it just continueson normally to print `I am here`. You can see in the output that the result is thatboth lines are displayed.<jupyter_code>sun = "down"
if sun == "down":
    print("Good night!")
print("I am here")<jupyter_output>Good night!
I am here<jupyter_text>If you run the same code with some word other than **down** in the sun variable, thenthe first `print` is ignored, but the next line is still executed normally because it’snot dependent on the condition being true.In the example below, it’s not **true** that the variable named `sun` contains **True**,therefore the rest of that line is ignored and only the next line is executed.<jupyter_code>sun = "up"
if sun == "down":
    print("Good night!")
print("I am here")<jupyter_output>I am here<jupyter_text>You can indent any number of lines under the `if`, and those indented lines execute only if the condition proves `true`. If the condition proves `false`, none of the indented lines are executed. The code under the indented lines is **always executed** because it’s not dependent on the condition. Here is an example where we have four lines of code that execute only if the condition proves `true`:<jupyter_code>total = 100
sales_tax_rate = 0.023
taxable = True
if taxable:
    print(f"Subtotal : ${total:.2f}")
    sales_tax = total * sales_tax_rate
    print(f"Sales Tax: ${sales_tax:.2f}")
    total = total + sales_tax
print(f"Total : ${total:.2f}")<jupyter_output>Subtotal : $100.00
Sales Tax: $2.30
Total : $102.30<jupyter_text>You must spell True and False with an initial capital letter and the rest lowercase. If you type it any other way, Python won’t recognize it as a Boolean True or False and your code won’t run as expected. Notice that in the `if` statement we used`if taxable:`This is perfectly okay because we made taxable a Boolean that can only be `True` or `False`. You may see it shown as`if taxable == True:`This also works. The `== True` is just unnecessary because, by itself, taxable is already either `True` or `not False`.  Adding else to your if statementSo far we’ve looked at code examples in which some code is executed if some condition proves `true`. If the condition proves `false`, then that code is ignored. Sometimes, you may have a situation where you want one chunk of code to execute if a condition proves `true`, otherwise (`else`) if it doesn’t prove `true`, you want some other chunk of code to be execute. In that case, you can add an `else:` to your `if`. Any lines of code indented under the `else:` are executed only if the condition did not prove true. Here is the logic and syntax: `if condition:    do indented lines here    ...else:    do indented lines here    ...do remaining un-indented lines no matter what.` The code below shows a simple example where we grab the current time from the computer clock using `datetime.now()`. If the hour of that time is less than 12, then the program shows **Good morning!** Otherwise, it shows **Good afternoon!**.Regardless of the hour, it prints **I hope you are doing well**. So if you write sucha program and run it in the morning, you get the appropriate greeting followed by**I hope you are doing well!**.<jupyter_code>import datetime as dt

# Capture current date and time
now = dt.datetime.now()

# Make a decision based on the hour value of DateTime
if now.hour <12:
    print("Good morning!")
else:
    print("Good afternoon!")
print("I hope you are doing well!")<jupyter_output>Good afternoon!
I hope you are doing well!<jupyter_text>Handling multiple else’s with elifBut what if it’s 11:00 at night? Do you really want to say “Good afternoon”? What we need is an `if . . . else` where there are multiple else’s possible. That’s where the `elif` statement comes into play.An `if` statement can include any number of `elif` conditions. You can include or not include a final `else` statement that executes only if the `if` and all the previous `elifs` prove `false`. In its simplest form, the syntax for an `if` with `elif` and `else` is >`if condition:>    do these indented lines of code>    ...>elif condition>    do these indented lines of code>    ...>do these un-indented lines of code no matter what.`<jupyter_code># Capture current date and time
now = dt.datetime.now()

# Make a decision based on the hour value of DateTime
if now.hour <12:
    print("Good morning!")
elif now.hour > 11 and now.hour< 18:
    print("Good afternoon!")
else:
    print("Good evening!")
print("I hope you are doing well!")<jupyter_output>Good afternoon!
I hope you are doing well!<jupyter_text>Here's another example of why `elif:` is important.Sometimes it is possible that none of our code will execute. Here's a traffic light example.<jupyter_code>light_colour = "green"
if light_colour == "green":
    print("Go")
elif light_colour == "red":
    print("Stop")
print("This code executes no matter what")<jupyter_output>Go
This code executes no matter what<jupyter_text>And changng the light coliur to **red** does this:<jupyter_code>light_colour = "red"
if light_colour == "green":
    print("Go")
elif light_colour == "red":
    print("Stop")
print("This code executes no matter what")<jupyter_output>Stop
This code executes no matter what<jupyter_text>If we change the light colour to **amber**, then this happens:<jupyter_code>light_colour = "amber"
if light_colour == "green":
    print("Go")
elif light_colour == "red":
    print("Stop")
print("This code executes no matter what")<jupyter_output>This code executes no matter what<jupyter_text>Executing this code does not rersult in **green** or **red** output, because neither colour==“green” or colour==“red” prove true, so none of the indented code was executed. We can add an `else` option that happens **only if** the previous conditions all prove**false**, like this:<jupyter_code>light_colour = "amber"
if light_colour == "green":
    print("Go")
elif light_colour == "red":
    print("Stop")
else:
    print("Proceed with caution")
print("This code executes no matter what")<jupyter_output>Proceed with caution
This code executes no matter what<jupyter_text>The fact that the `light_colour` is **amber** prevents the first two `if` conditions fromproving true, so only the `else` code is executed. And that’s true for anything youput into the light_colour variable because the `else` isn’t looking for a specificcondition. It’s just providing an **if all else fails, do this** role in the program logic.  Using a FOR loopDecision-making is a big part of writing program code. But there are also cases where you need to count or perform some task over and over. A `for` loop is one way to do that. Itallows you to repeat a line of code, or several lines of code, as many times as youlike.  Looping through numbers in a rangeIf you know how many times you want a loop to repeat, using this syntax may be easiest: >`for x in range(y):>    do this>    do this>    ...>un-indented code is executed after the loop` Replace `x` with any variable name of your choosing. Replace `y` with any numberor range of numbers. If you specify one number, the range will be from zero to one less than the final number.<jupyter_code>for x in range(7):
    print(x)
print("Loop finished")<jupyter_output>0
1
2
3
4
5
6
Loop finished<jupyter_text>If you want to run the loop within a specific range of numbers, we can put two numbers, separated by a comma, as the range. The first number is where the counting for the loop starts. The second number is **one greater** than where the loop stops. For example, here is a `for` loop with two numbers in the range:<jupyter_code>for x in range(1, 10):
    print(x)
print("All done")<jupyter_output>1
2
3
4
5
6
7
8
9
All done<jupyter_text>Looping through a stringUsing `range()` in a `for` loop is optional. You can replace `range` with a `string`, andthe loop repeats **once for each character in the string**. The variable `x` (or whateveryou name the variable) contains one character from the string with each pass through the loop, going from left to right. The syntax is: >`for x in string:>    do this>    do this>    ...>Do this when the loop is done` The string should be text enclosed in quotation marks, or it should be the name of a variable that contains a string.<jupyter_code>for x in "Letterkenny":
    print(x)
print("Done")<jupyter_output>L
e
t
t
e
r
k
e
n
n
y
Done<jupyter_text>The string doesn’t have to be a literal string. It can be the name of any variable that contains a string. For example, try this code:<jupyter_code>my_word = "Letterkenny"
for x in my_word:
    print(x)
print("Done")<jupyter_output>L
e
t
t
e
r
k
e
n
n
y
Done<jupyter_text>Looping through a listA `list` in Python is any group of items, separated by commas, inside square brackets. You can loop through a list either directly in the `for` loop or through a variable that contains the list. Here is an example of looping through the list with no variable:<jupyter_code>for x in ["I", "like", "Natural", "Language", "Processing"]:
    print(x)
print("Done")<jupyter_output>I
like
Natural
Language
Processing
Done<jupyter_text>We can assign the `list` to a variable too, and then use the variable name in the `for` loop rather than the list. Below is an example where the variable is assigned a list of text as before. Again, notice how the list is contained within square brackets. These are what make Python treat it as a `list`.The `for` loop then loops through the list, printing each word (one item in the list) with each pass through the loop. We used the variable name `sentence` rather than `x`, but that name can be any valid name you like. We could have used`x` or anything else, so long as the variable name that represents the list matches the name used in the `for` loop.<jupyter_code>sentence = ["I", "like", "Natural", "Language", "Processing"]
for word in sentence:
    print(word)
print("sentence finished.")<jupyter_output>I
like
Natural
Language
Processing
sentence finished.<jupyter_text>Stopping a loop during executionTypically, you want a loop to go through an entire list or range of items, but you can also force a loop to stop early if some condition is met. Use the `break` statement inside an `if` statement to force the loop to stop early. The syntax is: >`for x in items:>    if condition:>        [do this ... ]>        break>    do this>do this when loop is finished` Here's an example where we are chacking for missing text in a list.<jupyter_code>sentence = ["I", "like", "Natural", "Language", "Processing"]
for word in sentence:
    if word == "":
        print("missing")
        break
    print(word)
print("Loop is complete")<jupyter_output>I
like
Natural
Language
Processing
Loop is complete<jupyter_text>Here's the same code with a missing value added to the list.<jupyter_code>sentence = ["I", "like", "", "Language", "Processing"]
for word in sentence:
    if word == "":
        print("missing")
        break
    print(word)
print("Loop is complete")<jupyter_output>I
like
missing
Loop is complete<jupyter_text>The logic is, as long as there is some word provided, the `if` code is not executed and the loop runs to completion. However, if the loop encounters a blank word, it prints **missing** and also **breaks** the loop, jumping down to thefirst statement outside the loop (the final un-indented code), which displays **Loop is complete**.  Looping with continueYou can also use a `continue` statement in a loop, which is kind of the opposite of `break`. Whereas `break` makes code execution jump past the end of the loop and stop looping, `continue` makes it jump back to the top of the loop and continue with the next item (that is, after the item that triggered the continue). Here's the same code as the previous example, but instead of executing a break when it hits a blank answer, it continues with the next item in the list:<jupyter_code>sentence = ["I", "like", "", "Language", "Processing"]
for word in sentence:
    if word == "":
        print("missing")
        continue
    print(word)
print("Loop is complete")<jupyter_output>I
like
missing
Language
Processing
Loop is complete<jupyter_text>The code doesn’t print the blank answer, it prints **missing**, but then it goes back and continues looping through the rest of the items on the list.  Nesting loopsIt’s perfectly okay to nest loops . . . that is, to put loops inside of loops. Just make sure you get your indentations right because only the indentations determine which loop, if any, a line of code is located within. For example, in this code, an outer loop loops through the words First, Second, and Third. With each pass through the loop, it prints a word, then it prints the numbers 1–3 (by looping through a range and adding 1 to each range value).So you can see, the loops work because we see each word in the outer list followed by the numbers 1–3. The end of the loop is the first un-indented line at the bottom, which doesn’t print until the outer loop has completed its process.<jupyter_code># Outer loop
for outer in ["first loop", "second loop", "third loop"]:
    print(outer)
    # Inner loop
    for inner in range(1, 10):
        print(inner)
        
print("Both loops are now complete")<jupyter_output>first loop
1
2
3
4
5
6
7
8
9
second loop
1
2
3
4
5
6
7
8
9
third loop
1
2
3
4
5
6
7
8
9
Both loops are now complete<jupyter_text>Looping with whileAs an alternative to looping with `for`, you can loop with `while` instead. The difference is subtle. With `for`, we generally get a fixed number of loops, one for each item in a `range` or one for each item in a `list`. With a `while` loop, the loop keeps going as long as (while) some condition is true. Here is the basic syntax: >`while condition>    do this ...>    do this ...>do this when loop is done` With `while` loops, we have to make sure that the condition that makes the loop stop happens eventually. Otherwise, we get an **infinite loop** that just keeps going until some error causes it to fail, or until we force it to stop.<jupyter_code>counter = 50
while counter <60:
    print(counter)
    counter += 1

print("Loop complete")<jupyter_output>50
51
52
53
54
55
56
57
58
59
Loop complete<jupyter_text>A common mistake to make with this kind of loop is to forget to increment the counter so that it grows with each pass through the loop and eventually makes the while condition false and stops the loop. If we were to remove the `counter += 1` line of code, the loop would always remain less then 60 and the loop would run indefinitely.  Starting while loops over with continueWe can use `if` and `continue` in a `while` loop to skip back to the top of the loop just as we can with for loops. Take a look at this code for an example.The `int()` function returns only the whole portion of a number. If the random number that gets generated is 5, then dividing this number by 2 gets you 2.5. Then `int(number)` is 2 because the `int()` of a number drops everything after the decimal point. 2 does not equal 2.5, so the code skips over the `continue`, prints that odd number, incrementsthe counter, and keeps going.If the next random number is 12, then 12 divided by 2 is 6 and `int(6)` does equal 6 (since neither number has a decimal point). That causes the `continue` to execute, skipping over the `print(number)` statement and the counter increment,so it just tries another random number and continues. Eventually, it finds 10 odd numbers, at which point the loop stops.<jupyter_code>import random
print("list of 10 random odd numbers between 0 - 100")
num_count = 0

while num_count < 10:
    # get random number is 1-100 range
    random_number = random.randint(1,100)
    # Check whether an int conversion of the random
    # number is the same as the random number
    if int(random_number / 2) == random_number / 2:
        # The number will not be printed as the
        # program skips back to the start of the
        # while loop if the number is even
        continue
    print(random_number)
    # increment counter
    num_count +=1
    
print("10 random numbers shown.")<jupyter_output>list of 10 random odd numbers between 0 - 100
89
31
55
37
45
51
41
61
73
99
10 random numbers shown.<jupyter_text>Breaking while loops with breakYou can also `break` a `while` loop using `break`, just as you can with a `for` loop. When you `break` a `while` loop, you force execution to continue with the first line of code that’s under and outside the loop, thereby stopping the loop but continuing the flow with the rest of the action after the loop.Another way to think of a `break` is as something that allows you to stop a while loop before the `while` condition proves `false`. So it allows you to literally break out of the loop before its time. However this situation is very unusual where breaking out of a loop before its time was a good solution to the problem, so it’s hard to come up with a practical example. >`while condition1:>do this.>...>if condition2>break>do this code when loop is done` There are two things that can stop this loop. Either `condition1` proves `False`, or `condition2` proves `True`. Regardless of which of those two things happen, code execution resumes at the first line of code outside the loop, the line that reads do this code when loop is done in the sample syntax. Here is an example where the program prints up to ten numbers that are evenly divisible by five. It may print fewer than that, though, because when it hits a random number that’s evenly divisible by five, it stops the loop. So the onlything you can predict about it is that it will print between zero and ten numbers that are evenly divisible by five. You can’t predict how many it will print on any given run, because there’s no way to tell if or when it will get a random number that’s evenly divisible by five during the ten tries it’s allowed:<jupyter_code>import random
print("Numbers that aren't evenly divisible by 5")
counter = 0
while counter < 10:
    # Get a random number
    number = random.randint(1,999)
    if int(number / 5) == number / 5:
        # If it's evenly divisible by 5, bail out.
        break
    # Otherwise, print it and keep going for a while.
    print(number)
    # Increment the loop counter.

    counter += 1
print("Loop is done")<jupyter_output>Numbers that aren't evenly divisible by 5
41
892
858
317
877
503
Loop is done
{'fraction_non_alphanumeric': 0.07669835611012081, 'fraction_numerical': 0.010992275698158051, 'mean_word_length': 4.20541237113402, 'pattern_counts': {'":': 14, '<': 75, '<?xml version=': 0, '>': 106, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '22', 'dir': 'jupyter-structured-clean-dedup', 'id': '524972', 'license': 'MIT', 'n_tokens_mistral': 5690, 'n_tokens_neox': 5446, 'n_words': 3119, 'path': 'Program/decisionmaking.ipynb', 'repo_name': 'lavishthomas/AICourse', 'size': '20196'}