Lecture 5: Loops

CSCI 1360: Foundations for Informatics and Analytics

Overview and Objectives

In this lecture, we'll go over the basics of looping in Python. By the end of this lecture, you should be able to

  • Perform basic arithmetic operations using arbitrary-length collections
  • Use "unpacking" as a shortcut for iterating through dictionaries
  • Describe the differences between the separate kinds of loops

Part 1: for Loops

Looping, like lists, is a critical component in programming and data science. When we're training models on data, we'll need to loop over each data point, examining it in turn and adjusting our model accordingly regardless of how many data points there are. This kind of repetitive task is ideal for looping.

Let's define for ourselves the following list:


In [4]:
ages = [21, 22, 19, 19, 22, 21, 22, 31]

This is a list containing the ages of some group of students, and we want to compute the average. How do we compute averages?

We know an average is some total quantity divided by number of elements. Well, the latter is easy enough to compute:


In [7]:
number_of_elements = len(ages)
print(number_of_elements)


8

The total quantity is a bit trickier. You could certainly sum them all manually--


In [5]:
age_sum = ages[0] + ages[1] + ages[2] # + ... and so on

...but that seems really, really tedious. Plus, how do you even know how many elements your list has?

Loop structure

The structure itself is pretty simple:

  • some collection of "things" to iterate over
  • a placeholder for the current "thing"
  • a chunk of code describing what to do with the current "thing"

Let's start simple: looping through a list, printing out each item one at a time.


In [1]:
for N in [2, 5, 7, 9]:  # Header
    print(N)            # Body


2
5
7
9

There are two main parts to the loop: the header and the body.

  • The header contains 1) the collection we're iterating over (in this example, the list), and 2) the "placeholder" we're using to hold the current value (in this example, N).
  • The body is the chunk of code under the header (indented!) that executes on each iteration.

Back, then, to computing an average:


In [8]:
age_sum = 0
ages = [21, 22, 19, 19, 22, 21, 22, 31]

for age in ages:
    age_sum += age

avg = age_sum / number_of_elements  # Compute the average using the formula we know and love!
print("Average age: {:.2f}".format(avg))


Average age: 22.12

You can loop through sets and tuples the same way.


In [36]:
s = set([1, 1, 2, 3, 5])
for item in s:
    print(item)


1
2
3
5

In [37]:
t = tuple([1, 1, 2, 3, 5])
for item in t:
    print(item)


1
1
2
3
5

Iterators

The unifying theme with all these collections you can loop through is that they're all examples of iterators.

Easily the most common iterator you'll use (aside from lists, sets, and tuples) is the range function:


In [2]:
for i in range(10):
    print(i, end = " ")  # Prints everything on 1 line.


0 1 2 3 4 5 6 7 8 9 

Note, again, that the range of numbers goes from 0 (inclusive) to the specified end (exclusive)! The critical point is that the argument to range specifies the length of the returned iterator.

A few more examples of range before we get back to loops:


In [3]:
for i in range(5):  # One argument: specifies the "end"
    print(i, end = " ")


0 1 2 3 4 

In [4]:
for i in range(5, 10):  # Two arguments: first is "start" (inclusive), second is "end" (exclusive)
    print(i, end = " ")


5 6 7 8 9 

In [5]:
for i in range(0, 10, 2):  # Three arguments: start, end, and increment
    print(i, end = " ")


0 2 4 6 8 

IMPORTANT: INDENTATION MATTERS

You'll notice in these loops that the loop body is distinctly indented relative to the loop header. This is intentional and is indeed how it works! If you fail to indent the body of the loop, Python will complain:


In [48]:
some_list = [3.14159, "random stuff", 4200]
for item in some_list:
print(item)


  File "<ipython-input-48-e6ab552bd1f0>", line 3
    print(item)
        ^
IndentationError: expected an indented block

With loops, whitespace in Python really starts to matter. If you want many things to happen inside of a loop, you'll need to indent every line!

Let's say in some future homework assignment, I ask you to write a loop computing the squares of the numbers 1-10. How would you do it?

Well, you could manually write it out, I suppose...


In [39]:
squares = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

...but that's awfully boring.

Instead, let's use the range function we were just discussing:


In [9]:
squares = []  # Empty list for all our squares

for num in range(10):
    squared_number = num ** 2  # Exponent operation!
    squares.append(squared_number)  # Add to our list.

print(squares)


[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Looping through dictionaries

This gets its own subsection because it pulls together pretty much all the concepts we've discussed so far: lists, tuples, dictionaries, and looping.

Let's start by defining a dictionary. In this case, we'll set up a dictionary that maps people to their favorite programming language.


In [43]:
favorite_languages = {
    'jen': 'python',
    'sarah': 'c',
    'edward': 'ruby',
    'shannon': 'python'
}
# Notice the indentation, if you decide to define a dictionary this way!

Remember the super-useful methods for iterating through dictionaries? keys gives you a list of all the keys, values a list of all the values, and items a list of tuples of the key-value pairs. Here's the loop:


In [44]:
for key, value in favorite_languages.items():  # 1
    print("{} prefers {}.".format(key, value))


sarah prefers c.
shannon prefers python.
jen prefers python.
edward prefers ruby.

1: Notice how key, value are just out there floating! This is called unpacking and is a very useful technique in Python. If I have a list of a few items, and (critically) I know how many items there are, I can do this


In [45]:
some_list = ['a', 'b']
a, b = some_list

instead of this


In [46]:
some_list = ['a', 'b']
a = some_list[0]
b = some_list[1]

In the same vein, I could have just as easily written the loop like this:


In [47]:
for keyvalue in favorite_languages.items():  # 1
    key = keyvalue[0]
    value = keyvalue[1]
    print("{} prefers {}.".format(key, value)) # 2


sarah prefers c.
shannon prefers python.
jen prefers python.
edward prefers ruby.

and indeed, if that is easier for you to understand, by all means do it! This is to illustrate all the concepts at play at once:

  • the loop header iterates through a list provided by favorite_languages.items()
  • each iteration, items() provides a tuple: a key-value pair from the dictionary
  • we can "unpack" these variables using shorthand, but it's also perfectly valid to do it the "regular" way

That's pretty much for loops!

What about the case where you don't know ahead of time how many iterations your loop will take?

Part 2: while Loops

"While" loops go back yet again to the concept of boolean logic we introduced in an earlier lecture: loop until some condition is reached.

The structure here is a little different than for loops. Instead of explicitly looping over an iterator, you'll set some condition that evaluates to either True or False; as long as the condition is True, Python executes another loop.


In [6]:
x = 10

while x < 15:
    print(x, end = " ")
    x += 1


10 11 12 13 14 

x < 15 is a boolean statement: it is either True or False, depending on the value of x. Initially, this number is 10, which is certainly < 15, so the loop executes. 10 is printed, x is incremented, and the condition is checked again.

A potential downside of while loops: forgetting to update the condition inside the loop.

It's easy to take for granted; for loops implicitly handle this for us!


In [7]:
for i in range(10, 15):
    print(i, end = " ")
    # No update needed!


10 11 12 13 14 

Use for loops frequently enough, and when you occasionally use a while loop, you'll forget you need to update the loop condition.

Review Questions

Some questions to discuss and consider:

1: Using the awful matrix construct of a "list of lists," show how you could write loops that double the value of each element of the matrix.

2: for and while loops may have different syntax and different use cases, but you can often translate the same task between the two types of loops. Show how you could use a while loop to iterate through a list of numbers from range().

3: Let's say you have two lists, K and V, that are both the same length. Show how, using only 1 loop, you can loop through both of them simultaneously.

4: Now let's say your lists K and V are not the same length. Using 1 loop, iterate through them, stopping when you reach the end of the shorter list.

Course Administrivia

A1 is out!

Even though A0 isn't "graded", please submit by 11:59 tonight.

Next week: generators and comprehensions and enumerate, oh my!

Additional Resources

  1. Matthes, Eric. Python Crash Course. 2016. ISBN-13: 978-1593276034
  2. Grus, Joel. Data Science from Scratch. 2015. ISBN-13: 978-1491901427