## Do it again! Loops in Python Repetitive tasks are boring. Also, repetitive tasks are prone to errors. I could copy and paste values in a spreadsheet, but for every 100 things I do, 5 of them would be wrong. The number of errors goes up for more complex tasks. Fortunately, computers are really good at repetitive tasks and they don’t make errors, whether they copy and paste things 100 or 1000 times.

A useful programming tool that helps with repetitive tasks is `for` loops. Every programming language has a version of `for` loops, and Python is no exception. This tutorial will provide a simple introduction to Python `for` loops and give a few examples of how they can be used to automate and reduce errors in everyday research tasks.

### The most basic for loop

As scientists, we often have columns of data representing different subjects, experiments, samples, etc. Before reporting results or running statistical analysis, we may want to do some calculations, normalize the numbers, or simply have a look at each value. Rather than typing the same command over and over for each value of interest, we can type the command once and apply it to each value using a `for` loop.

Here is a simple example.

```for i in [0, 1, 2, 3, 4]:
print(i)
```

In this `for` loop, the variable `i` sequentially takes on each value in the list provided. The first time through the loop, `i` will be equal to `0`, so `print(i)` is equivalent to `print(0)` in this case. The next time through the loop, `i` will be equal to `1`. This continues until `i` has taken on each value in the list we provided, in this case `[0, 1, 2, 3, 4]`. Note the colon at the end of the first line and indented text. All the text that is indented will be executed each time through the loop.

A slight variation of this `for` loop is to use the `range()` command. It provides a series of numbers without having to write them all out. The most basic use is `range(value)`, which creates a list from `0` to `value - 1`. So `range(5)` generates `0, 1, 2, 3, 4`. Range also allows the user to specify the start, stop and step size. For example, `range(2,11,2)` generates `2, 4, 6, 8, 10`.

Here is a slightly more complex `for` loop with the `range()` command that executes multiple commands each loop. Note that the final `print()` statement is not indented; it is only executed once and uses the final value of `i`.

```for i in range(5):
print(i)
print (i + i)
print (i - 4)
```

### A (slightly) more useful example of for loops

Lets say we have collected weight data from 5 subjects. First, let’s use a `for` loop to print these values.

```weights = [65, 82, 56, 110, 97]
# A simple for loop
for weight in weights:
print(weight)
# Same output, but using range() and indexing weight
for i in range(5):
print(weights[i])
# Same output, but using len() and indexing weight
# len() returns the length of the list
for i in range(len(weights)):
print(weights[i])
```

It can sometimes be useful to iterate over each item of a list, but also have access to the current loop number. This functionally is made available via the `enumerate()` command.

```for i, weight in enumerate(weights):
print(i, weight)
```

### Using for loops to calculate subjects BMI

Lets add the height of our subjects. Once again, we want to print these values, along with the weight data. One option is to use `for i in range(5):` and have two indented print statements: `print(weight[i])` and `print(height[i])`. Because iterating over two or more lists of the same length is so common, Python has a `zip()` command to do just that.

```heights = [165, 178, 199, 182, 174]
for weight, height in zip(weights, heights):
print(weight, height)
```

With each subject’s height and weight, we can calculate their Body Mass Index (BMI). Lets do that using a `for` loop. Note that `**2` is raising the value to the power 2 (i.e., squaring the value). Also, we divide height by 100 to convert centimeters into meters.

```for weight, height in zip(weights, heights):
bmi = weight / ((height)/100)**2
print('BMI = ', bmi)
```

Because looping over one or more list and computing new values is so common, Python has something called list comprehension that allows us to create a `for` loop on a single line of code. The basic structure is pretty simple:

```new_variable = [f(i) for i in x]
```

This will create a new variable, where each element is the result of applying a function `f()` to each value of `x`. A more familiar example would be:

```height_meters = [height/100 for height in heights]
print(height_meters)
```

Now let’s use list comprehension to compute and store the BMI of each subject.

```bmi = [w/h**2 for w, h in zip(weights, height_meters)]
print (bmi)
```

### Summary

We learned how to use Python `for` loops to do repetitive tasks. We also saw that Python has various helper functions, such as `enumerate()`, `range()`, `zip()`, and list comprehension, that make `for` loops more powerful and easier to use. Can you think of a few processing steps that you currently do by hand that could be automated using `for` loops? Once you understand the power of `for` loops, you will see them everywhere!