We discussed the while loop, and learned some basic strategies for writing code with loops.
We now move on to discuss the for
loop, a common way of iterating over complex data structures, (e.g., lists, set, dictionaries, etc.) that we examined.
In Python, the for statement allows us to write programs that implement iteration.
As a simple example, let’s say we have the names of the students in the class, and we want to send them a notification that we posted an assignment online and that the deadline is in a week.
We do not want to write manually repeat the process of writing an email separately for each student, so we use a loop for that:
students = ["Joe", "Amy", "Brad", "Maria", "Sophia", "Michael"]
for name in students:
print("Hi", name)
print("The assignment is now posted online.")
print("The deadline is in one week.")
print("Cheers,\nPanos")
print("------")
print("Done!")
Let's examine the structure of the loop:
name
variable is called the loop variable or iteration variable.name
variable changes in each iteration of the loop. It will iteratively take the value of each of the six values in the students
list.name
will refer to a different student.In a more formal way, the flowchart below illustrates the execution order and logic in a for
statement:
It is very important to grasp the concept of the loop variable, and understand that it will iteratively take the value of all the elements in the list. In fact, it is not necessary to iterate over a list. We can also iterate over sets, dictionaries, and other composite data structures. Let's see some examples next.
Write a program that uses a for loop to print
One of the months of the year is January
One of the months of the year is February
One of the months of the year is March
months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
]
# your code here
months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
]
for month in months:
print("One of the months of the year is", month)
Assume you have a list of numbers 12, 10, 32, 3, 66, 17, 42, 99, 20
numbers = [12, 10, 32, 3, 66, 17, 42, 99, 20]
# your code here
# Write a loop that prints each of the numbers on a new line.
numbers = [12, 10, 32, 3, 66, 17, 42, 99, 20]
for number in numbers:
print(number)
# Write a loop that prints each number and its square on a new line.
numbers = [12, 10, 32, 3, 66, 17, 42, 99, 20]
for number in numbers:
print(number, "==>", number * number)
Often it is convenient to define (and iterate through) ranges of integers. Python has a convenient range
function that allows you to do just this. The range
function allow us to generate a list of numbers:
list(range(10))
print(list(range(10))) # start at zero, < the specified ceiling value
for i in range(10):
print(i, "squared is", i * i)
When range command has two parameters, it starts from the first parameter and finishes at the second
# from the left value, < right value
print(list(range(-5, 5)))
# range(10) is the same at range(0,10)
print(list(range(10)))
print(list(range(0, 10)))
When range has a third argument, this is the "step" value
# from the left value, to the middle value, incrementing by the right value
print(list(range(-5, 50, 5)))
Perhaps some of you, already familiar with programming, will tend to write code like this:
# Old style, using indexing for loops
names = ["Abe", "Bill", "Chris", "Dorothy", "Ellis"]
for i in range(0, len(names)):
print(names[i])
instead of
# Pythonic style, use iterators
names = ["Abe", "Bill", "Chris", "Dorothy", "Ellis"]
for n in names:
print(n)
Avoid using the indexing style method for iterating through data structures. While technically both generate the same result, the "Pythonic" way of doing things is the latter: It is simpler, more readable, and less prone to errors.
print(i*'#')
will print the character '#' a total of i
times.#
##
###
####
#####
######
#######
########
#########
##########
# Notice that the loop variable "i"
# is not used within the loop
for i in range(10):
print("Panos!")
# Sometimes, when the loop variable is not
# used within the loop, the convention is to use
# underscore _ as the variable name. (Yes, it is a valid variable name)
for _ in range(10):
print("Panos!")
for i in range(10):
print(i * "#")
for i in range(10):
print((i + 1) * "#")
for i in range(1, 11):
print(i * "#")
The for
statements are a convenient way to iterate through the values contained in a data structure.
Let's see now examples for iterating over lists, sets, and dictionaries.
We have already gone through some simple examples, so let's work on a bit more elaborate example.
We have a list with the names of the NBA teams. We want to process all of them, and extract the "franchise" name (e.g., Knicks
is the franchise name for NY Knicks). For all (current) NBA teams, the franchise name is the last part of the team name. Let's see how we can do that:
nba_teams = [
"Atlanta Hawks",
"Boston Celtics",
"Brooklyn Nets",
"Charlotte Hornets",
"Chicago Bulls",
"Cleveland Cavaliers",
"Dallas Mavericks",
"Denver Nuggets",
"Detroit Pistons",
"Golden State Warriors",
"Houston Rockets",
"Indiana Pacers",
"LA Clippers",
"Los Angeles Lakers",
"Memphis Grizzlies",
"Miami Heat",
"Milwaukee Bucks",
"Minnesota Timberwolves",
"New Orleans Pelicans",
"New York Knicks",
"Oklahoma City Thunder",
"Orlando Magic",
"Philadelphia 76ers",
"Phoenix Suns",
"Portland Trail Blazers",
"Sacramento Kings",
"San Antonio Spurs",
"Toronto Raptors",
"Utah Jazz",
"Washington Wizards",
]
print("The list contains", len(nba_teams), "teams")
Let's see an example of processing a single team name to get the franchise name:
team = "Atlanta Hawks"
team_words = team.split()
print(team_words)
franchise = team_words[-1]
print(franchise)
Notice that we should use -1 as the index to get the last word, and not try to get the second word, as this would not work with team names such as "New York Knicks" or "Los Angeles Lakers".
team = "Los Angeles Lakers"
team_words = team.split()
franchise = team_words[-1]
print(team_words)
print(franchise)
So, now we take the code for extracting the franchise name, and put it within the loop:
for team in nba_teams:
franchise = team.split()[-1]
print(team, "\t ==>\t", franchise)
The process of iterating through sets and tuples is pretty much identical to the one for lists. Let's see a few examples.
# Iterating over a set
print("Print all numbers in the set, and their square")
set_a = {1, 2, 3, 4, 5, 6}
for i in set_a:
print(i, " squared is:", i * i)
print("A more complex block: Only print squares of even numbers")
set_a = {1, 2, 3, 4, 5, 6}
for i in set_a:
# print(i)
if i % 2 == 0:
print("==> ", i, " squared is:", i * i)
# Iterating over a tuple
print("Print all numbers in the tuple, and their square")
tuple_a = (1, 2, 3, 4, 5, 6)
for i in tuple_a:
print(i, " squared is:", i * i)
Iterating through dictionaries is a bit more complex. You can iterate through keys, values, or both.
Here is an dictionary, which we will use as an example. It contains names as keys, and phone numbers as corresponding values.
phones = {
"Panos": "212-998-0803",
"Maria": "656-233-5555",
"John": "693-232-5776",
"Jake": "415-794-3423",
}
By default, when we iterate over a dictionary, we are iterating over the keys.
print("Iterating over keys")
for k in phones:
print("key =", k, ", value =", phones[k])
print("Iterating over keys, more explicit")
for k in phones.keys():
print("key =", k, ", value =", phones[k])
If you want to print the keys in alphabetical order, you first make a list of the keys in the dictionary using the keys method available in dictionary objects, and then sort that list and loop through the sorted list, looking up each key and printing out key-value pairs in sorted order as follows:
print("Iterating over sorted keys")
sorted_keys = sorted(phones.keys())
for k in sorted_keys:
print("key =", k, ", value =", phones[k])
It is also possible to iterate over the values for the dictionary:
print("Iterating over values")
for v in phones.values():
print(v)
Notice that when we iterate over the keys of a dictionary, we tend to use the phones[k]
structure to get the value associated with the key k
.
print("Iterating over both keys and values")
# Items returns *tuples* that correspond to key-value pairs
# ("Panos", "212-998-0803"), ("Maria": "656-233-5555"), etc.
# Notice that we have a *tuple* (k,v) now as a loop variable, and the tuple
# has two entries, the key k and the value v
for (k, v) in phones.items():
print(k, v)
# Rewriting, with a bit more descriptive variable names
for (name, phone) in phones.items():
print("Name:", name, "Phone:", phone)
# If you are confused with the (k,v) being the loop variable
# you can see the same loop where the loop variable is "item"
# Then we access the two elements of the tuple within the body
# of the loop name = item[0] and phone = item[1]
for item in phones.items():
name = item[0]
phone = item[1]
print("Name:", name, "Phone:", phone)
Let's work on an exercise now, showing how we can iterate through a nested data structure.
You are given the composite data structure below:
data = {
"Foster": {
"Job": "Professor",
"YOB": 1965,
"Children": ["Hannah"],
"Awards": ["Best Teacher 2014", "Best Researcher 2015"],
"Salary": 120000,
},
"Joe": {"Job": "Data Scientist", "YOB": 1981, "Salary": 200000},
"Maria": {
"Job": "Software Engineer",
"YOB": 1993,
"Children": [],
"Awards": [
"Dean's List 2013",
"Valedictorian 2011",
"First place in Math Olympiad 2010",
],
},
"Panos": {"Job": "Professor", "YOB": 1976, "Children": ["Gregory", "Anna"]},
}
## Print the names of people in the data
for name in data:
print(name)
for name in data.keys():
print(name)
## Print the names and age
for name in data.keys():
yob = data[name]["YOB"]
age = 2018 - yob
print("Name:", name, "\t", "Age:", age)
# Alternatively, using the data.items() approach
for name, entry in data.items():
yob = entry["YOB"] # instead of data[name], we use entry
age = 2018 - yob
print("Name:", name, "\t", "Age:", age)
## Print the names of people born after 1980
for name in data.keys():
yob = data[name]["YOB"]
if yob > 1980:
print("Name:", name)
## Print the number of children for each perspon
for name in data.keys():
# Get the value associated with the name (name = loop variable)
# The 'entry' variable is the value the key 'name'
# In our case, this is a dictionary with entries 'Job', 'YOB', etc
entry = data[name]
# If we do not check if 'Children' appears in entry, then we will get
# an error for 'Joe', whose dictionary does not have a 'Children' key
if "Children" in entry.keys():
num_children = len(entry["Children"])
else:
num_children = 0
print("Name:", name, "\t", "Children:", num_children)