Part Five: Loops
Tags: coding, python, programming, tutorial
Published: 2022-11-27 20:37:16

> "The definition of insanity is doing the same thing over and over and expecting different results." - _Albert Einstein_

---

Welcome to part five. In this series I hope to introduce the basics of coding in Python for absolute beginners in an easy to follow and hopefully fun way. In this article we will look at some of the ways we can design code which will make repetitive tasks quick and easy, but first let's take a look at the solution for the challenge set in part four.

---
**Solution to part four's challenge**

---

To solve the challenge, we need to use what we have learned about flow control, taking user input, and concatenation. The first task is to collect 3 pieces of information from the user - a first name, last name and their age. We will store each of these pieces of data in it's own variable.
```
first_name = input("First Name: ")
last_name = input("Last Name: ")
age = input("Age: ")
```
We now have first name, last name and age stored in separate variables. We are now asked to make some decisions based on their age to determine if they are old enough to do a certain activity. Our decision making will need something to compare the user's age to, so we make a fourth variable and assign the minimum age for our activity.
```
min_age = 18
```
Finally, to make our decision, we use an 'if / else' statement using our variables.
```
if age >= min_age:
    print("Hello " + first_name + " " + last_name + ", you are " 
    age + " and therefore old enough to vote in the UK where the 
    minimum age is " + min_age)
else:
    print("Sorry " + first_name + " " + last_name + ", you are " 
    age + " and therefore NOT old enough to vote in the UK where 
    the minimum age is " + min_age)
```

---
**Loops**

---
Loops as their name implies, are a way of running a piece of code again and again without the need to type everything out each time. For example, say I have a list of 100 animals and I want to print out each animal on the list. I could do it with a print statement for each item on the list:
```
my_list = ["badger", "woodcock", "pheasant", "pinemarten"...etc..]
print(my_list[0])
print(my_list[1])
print(my_list[2])
# ... and so on.
```
However, that's over 100 lines of code just to print a list! Apart from being time consuming to write, this would not be very fast or efficient from a software writing perspective.

A better way is to use a loop. Loops are a standard thing across programming languages and Python sports the usual two forms - 'while loops' and 'for loops'. 

---
**While Loops**

---

Let's look at while loops first. Going back to our list printing problem, we can use a while loop to do the hard work for us. While loops work like this:

_Do something for as long as a condition is valid_

Let's put this into practice so it makes more sense. Our while loop will keep doing something (in this case printing out list items) until our condition is no longer met. 

Here is the loop we will use. Have a read line by line and see if you can get a feel for how this is going to work. If not, don't worry I am going to go through each part below.
```
i = 0
while i < 100:
    print(my_list[i])
    i += 1
```
When this code runs the following happens:

1. The loop checks the value of `i` which starts at '0' and compares it to our condition which is `i` must be less than 100. As long as we meet this condition (i = 0 so is less than 100) we run the indented code below.
2. The code then prints the item in my_list with an index equal to `i` which is 0, so we print the first list item.
3. We then add 1 to `i` so it changes from 0 to 1.
4. The loop then runs again but this time `i` is equal to 1 which is still less than 100 so we run the indented code again.
5. The code prints the list item with the index of `i` which is now 1 and so we print the 2nd list item
6. We add 1 to `i` making it now 2
7. The loop runs again with `i` now equal to 2 and so on....

Let's go through it line by line.

Our variable `i` is effectively a counter to keep track of how many times we have run through the loop. You will often see this variable named 'i' or 'x' but in theory you can use any name you like:
```
i = 0 # remember the first index of a list is 0
```
OK, we have set our index variable to 0. Now we form our loop and set our condition to keep running through the loop. 
```
while i < 100:
```
Starting with the keyword `while` we say that while the value of `i` is less than 100 - keep running the indented code below the loop statement. Instead of 'i < 100' we could also use our other operators such as greater than (>), equal to (==), greater than or equal to (>=) etc.
```
    print(my_list[i])
    i += 1
```
In this  example our code prints a list item with an index equal to `i` which starts at 0. After the print statement, we increase `i` by adding 1 to it. The code `+=` is a short hand for adding 1 to something and is short for `i = i + 1`. We could increase our variable by any amount such as `i +=5` to increase in increments of 5. We can also count backwards using `-=`.

The whole thing would look like the following:
```
my_list = ["badger", "woodcock", "pheasant", "pinemarten"...etc..]

i = 0
while i < 100:
    print(my_list[i])
    i += 1

# Output
'badger'
'woodcock'
'pheasant'
'pinemarten'
# etc etc.
```

While loops are excellent for using where we must keep something going until a condition changes but there is a better way to loop through data structures such as lists and tuples - the 'for loop'.

---
**For Loops**

---

A for loop will automatically loop through a string, list, tuple etc even if we do not know how many items it contains. Whereas using a while loop requires us to set a condition for how many times we want to run the loop, the for loop does this for us. For loops effectively work in the following way:

_For each item in this string/list/tuple etc - do something_

Let's go back to our animal list and take a look at using a for loop. Again, take a look at it first and see if you can see how it will work.
```
my_list = ["badger", "woodcock", "pheasant", "pinemarten"...etc..]

for x in my_list:
    print(x)
```
A lot more compact isn't it? We do not need to create a counter variable or set the number of times to run through the loop, the for loop handles this for us. Each time the loop runs the following is happening:

1. The for loop automatically starts with the first list item at index 0 and stores the value of this item ('badger') in the variable `x`.
2. The loop then prints the value of `x` which is 'badger' to the screen.
3. The for loop now automatically moves to the next list item at index 1 and stores this item value in `x` ('woodcock').
4. The loop prints the value of `x` which is now 'woodcock' and so on....

Let's run through line by line:
```
for x in my_list:
```
We start with the keyword `for`. Next `x` is the name of a variable that exists only inside of the for loop. This variable could equally have been named `animal`, `species` or anything else we wanted. Each time the loop runs, the value of the item in my_list is stored in `x`.
```
print(x)
```
For each time through the loop, it prints the value of `x` which will be equal to the next list item each time through the list.

---
**A Note on infinite loops and the 'Do While' loop**

---
Whenever we use loops in our code we must be careful not to use loops which cannot satisfy the condition we set and therefore cannot end because we have not given a way to meet the condition. Consider the following loop:
```
i = 0
while i < 10:
    print(i)
```
This looks harmless enough right? Look closer, how will this loop end? We have not included a way to increment our index variable and so it's value will always be 0. Our condition states that while i is less than 10 the loop will continue to run. What we have created here is an 'infinite loop'. While in this example, we can simply press CTRL + C to exit out of the application, in more complex applications this can lead to all available memory being used up and the device will crash or freeze. Always make sure your loop is able to reach it's exit condition.

If you go on to code using other programming languages, you may come across another type of loop which is not natively part of Python - the do while loop. The do while loop is the same as a while loop with one key difference. A normal while loop has a condition which is checked at the start of the loop meaning if that condition is not met, the loop will never run. However, the do while loop puts this condition check at the end of the loop meaning the code contained in the loop will always run at least once. 

Do while loops can be approximated with workarounds in Python but for now I wouldn't worry about them, I just wanted to make you aware of what they are and how they work.

---
**Exercise**

---

Let's try putting loops into practice to show what they can do. Remember when we discussed slicing strings? I gave the example of writing code which would sort through livestock ID codes to give us data about the kinds of animals we had and their numbers. Well, let's write it now! Not only will this task use what we have learned using loops but it also introduces a new concept - using if / else statements with loops.

In this task you should imagine yourself in the role of a farmer or livestock manager taking inventory of their stock. You are presented with a list of ID tags which give each animal a letter determining their type and a unique ID number. The letters tell us the animal type as follows:

- 'B' - Bull
- 'H' - Heffer
- 'P' - Boar
- 'S' - Sow
- 'R' - Ram
- 'E' - Ewe

We need to write code which will analyse the list and determine 3 things:

1. How many animals of all types do we have?
2. How many of each type do we have?
3. How many total males and females of all species do we have?

In order to get you started I am going to generate the list for you. Delete any unwanted code from your IDE or create a new file. Copy and paste the following into the file:
```
import random

letters = ['B', 'H', 'P', 'S', 'R', 'Y']
stock = []
i = 0
while  i < 1000:
    letter = random.choice(letters)
    num = random.randint(100, 1000)
    stock.append(letter + str(num))
    i +=1
```
Don't worry how this works for now, just know that it is using a loop to generate a random list of codes for us to work with. As such, each time you run the code the list will be different so just bear that in mind if you get differing results.

So, we have our livestock list. Now we need to sort through it to determine what we have. If you feel confident then by all means have a go at solving this yourself using what you have learned. If not, or you want to follow along instead then read on.

Let's look at the problem first. We have a list of ID tags, each tag is comprised of a letter and a series of numbers. The numbers don't concern us, we are more interested in the letters as they denote the type of animal with that ID. We need to therefore loop through the list looking at the letter at the start of each item and then count the number of times each letter appears. To start, let's create variables to count each animal type:
```
bull = 0
heffer = 0
boar = 0
sow = 0
ram = 0
ewe = 0
```
Next we will create our loop which will do all of the hard work for us. This list is relatively small but in real life scenarios we could be dealing with lists with tens or even hundreds of thousands of items and making loops is a big time saver!
```
for count in stock:
    if count[0] == 'B':
        bull += 1
    elif count[0] == 'H':
        heffer += 1
    elif count[0] == 'P':
        boar += 1
    elif count[0] == 'S':
        sow += 1
    elif count[0] == 'R':
        ram += 1
    elif count[0] == 'E':
        ewe +=1
    else:
        pass
```
Yikes, that's a big loop! Well, yes but break it down line by line to simplify it. We have created a for loop and every time this loop runs we ask the question - is the first character (count[0]) of each list item equal to 'B'. If the answer is yes then we add 1 to our `bull` total. If the answer is no, we move to the next else / if statement which asks - is the first character of the list item equal to 'H'? Again, if the answer is yes we add 1 to our `heffer` total. If not we move onto the next option and so on. If we get all of the way through the loop and the list item has not been equal to any of our questions we reach the else statement and we move onto the next item.

Now to check if this has worked, we can print out our totals.
```
print("Total Bulls")
print(bull)
print("Total Heffers")
print(heffer)
print("Total Boars")
print(boar)
print("Total Sows")
print(sow)
print("Total Rams")
print(ram)
print("Total Ewes")
print(ewe)
```
All being well, you should see something like this in your output (remember each list is randomised so the numbers will be different):


![Stock](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w299m5ho2ny5n6lttl9x.jpg)

For an additional challenge, see if you can find a way to print the above figures in a more concise way like 'Total Bulls: 176'.

Next let's get a grand total for the number of animals we have and print this out below. This one should be easy for you:
```
grand_total = bull + heffer + boar + sow + ram + ewe
print("Total animals")
print(grand_total)
```
HINT: Maybe there is a way to create a line break between our species totals and grand total?

Finally, lets get our total males / females. Again, this should be fairly straight forward.
```
males = bull + boar + ram
females = heffer + sow + ewe
print("Total Males")
print(males)
print("Total Females")
print(females)
```
If your code is right you should have something like this in your output at the end (I included line breaks in mine):

![Stock totals](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6kc6wo1si52x37xmcjnw.jpg)

Umm, guys... we just wrote an application which could have been useful for something and accomplished a real world task! We are past the boring beginner stuff and we are now moving into subjects which enable us to deliver real solutions to real problems. With a bit of practice and imagination, we can begin to write software which can actually help ourselves and others. Getting totals for each animal type is just the tip of the iceberg of what we can do with out data now we have the ability to loop through it (known in programming as 'iterating'). If you are so inclined then I would encourage you to continue to add functionality to our code in order to manipulate the data in new and interesting ways.

---
**Challenge**

---
The challenge for next time is to write some code which will crack the code for an imaginary safe - all perfectly legal I assure you! I will give you a list of possible codes. All you need to do is run through the list until you find the right code to unlock the safe.
 
Here is the list of codes to get you started:
```
import random

code_list = []
i = 0
while i < 1000:
    num = random.randint(10000, 99999)
    code_list.append(num)
    i += 1
safe_code = random.choice(code_list)
```
The above code generates a list of 1000 possible codes to try and also picks one of those codes to be the actual safe code so you can't see it and cheat!

So, in summary write code which does the following:
1. Combs through the list of possible codes and tries to match each one to the actual safe code.
2. If the code matches print out something like "Safe cracked - code was 35865".
3. If the safe code does not match then the code should do nothing and run the loop again until the correct code is found.

---
**A Note On Password Cracking In Real Life**

---
Although we are just having fun here, this is basically a simplified version of brute force password cracking used by hackers to get into accounts. If you would like to check if the password you use for your online accounts is likely to be on a list of compromised passwords then you can create a similar application to the challenge above which does just that. Simply Google 'RockYou password list' and download this list or any other similar list. You can then import the file using Python (I will leave that up to you to discover how) and then check your password string against those in the list. If it's on the list, it's probably time to change it!

In case you are wondering, these password lists are used by penetration testers to make sure software and websites are secure and they are perfectly legal to download and use. However, if you are unsure then please check all applicable laws where you live before downloading anything.

---
**Conclusion**

---
Now we have begun to add flow control and loops to our code, I hope you are now starting to see that we are able to create useful applications that actually do something! I also hope that this is beginning to open your eyes to the possibilities when making your own projects. Take some time to become familiar with flow control and loops and then start to think of how they could be utilised in your own work or study to create applications to save time and work. In the next article, I will be discussing functions and methods which enable us to create re-usable chunks of code which can be inserted into our applications without needing to re-write everything each time.

Thank you for reading. As always, constructive feedback is always appreciated and I look forward to seeing you in part six.

Simon.