Iteration¶


infinite-face-palm.gif

Applied Review¶

Data Structures¶

  • Python has structures in which data is stored (list, dictionary, DataFrame, etc.)
  • Many of these structures are one-dimensional: list, dictionary, tuple, etc.
  • Others, like the DataFrame, can be represented as multiple one-dimensional structures
    • A single row
    • A single column
    • Column names
    • Row Index values (row numbers)

Control Flow¶

  • Control flow is controlling the flow of the program execution
  • One way to control program flow is with conditionals, but another way is iteration
  • Iteration is:
    • The repetition of a process
    • Usually repeated until a certain condition is met
  • An example is counting to 10

General Model¶

Iteration in a Program¶

  • Iteration can be used to control the flow of the program by repeating portions (blocks) of code

Form¶

  • Within programs, iteration usually takes the form of a loop (i.e. "Loop through this section of code...")
  • Iteration can also occur by applying a function over a sequence of inputs, and that will be covered in another module

Execution Pattern¶

Iterating N Times

iteration-execution-path.png

Iterating Through an Object

iteration-execution-path-2.png

Iterating Until a Condition is Met

iteration-execution-path-3.png

Why Use Iteration¶

Question: Why might we want to use iteration in Python?
  • Simplifies and condenses code by avoiding constant repetition
  • Avoid typos and mistakes by not needing to retype repeated tasks
  • Allows for automation where values may be unknown
  • This can be really beneficial when working with DataFrames:
    • Iterate over each column and perform a task
    • Iterate over each row and perform a task

Program Control¶

Iterating N Times¶

  • If we want to iterate N times, we can perform a for loop using the range() function:
In [1]:
for number in range(10):
    print(number)
0
1
2
3
4
5
6
7
8
9
  • This helps save code relative to:
In [2]:
print(0)
print(1)
print(2)
print(3)
print(4)
print(5)
print(6)
print(7)
print(8)
print(9)
0
1
2
3
4
5
6
7
8
9
  • Here the range() function results in a sequence of the numbers 0 through 9 (a range of 10 values)
In [3]:
list(range(10))
Out[3]:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  • The for loop block is then iterated 10 times, and the number variable represents the loop iteration number
  • The block is the indented section of code -- multiple lines can be indented
In [4]:
for number in range(4):
    print('\nThis is the next iteration:')
    print(number)
This is the next iteration:
0

This is the next iteration:
1

This is the next iteration:
2

This is the next iteration:
3

Your Turn¶

  1. What will be the value of number when this code finishes running?

    for number in range(10):
        print(number)
    
  2. Fill in the blanks below to make the code sum numbers 0 through 99.

    summation = 0
    for ______ in ______(______):
        summation = summation + number
    

Iterating Through Objects¶

  • We frequently want to do more complex things with iteration than just count or iterate N times...
  • Recall that many of our objects in Python are one-dimension sequences (lists, Series, tuples, etc.)
  • We can iterate through these sequential objects to perform an operation on each element

Iterating Through Each Element¶

  • We can iterate through sequences and access each element directly
In [5]:
neighborhoods = [
    'oakley', 'hyde park', 'clifton', 'corryville', 'northside'
]

for neighborhood in neighborhoods:
    print(neighborhood)
oakley
hyde park
clifton
corryville
northside
  • We've just been printing during iteration so far, but other functions are commonly used:
In [6]:
neighborhoods = [
    'oakley', 'hyde park', 'clifton', 'corryville', 'northside'
]
new_neighborhoods = []

for neighborhood in neighborhoods:
    new_neighborhoods.append(neighborhood.title())
    
new_neighborhoods
Out[6]:
['Oakley', 'Hyde Park', 'Clifton', 'Corryville', 'Northside']
  • Note the use of an empty list to store the updated value -- this is common practice

Iterating with enumerate()¶

  • We can access the element index and value by using the enumerate() function
In [7]:
neighborhoods = [
    'oakley', 'hyde park', 'clifton', 'corryville', 'northside'
]

for index, value in enumerate(neighborhoods):
    print(index, '-', value)
0 - oakley
1 - hyde park
2 - clifton
3 - corryville
4 - northside
  • This can be useful when we want to modify objects rather than create new ones
In [8]:
neighborhoods = [
    'oakley', 'hyde park', 'clifton', 'corryville', 'northside'
]

for index, value in enumerate(neighborhoods):
    neighborhoods[index] = value.title()

neighborhoods
Out[8]:
['Oakley', 'Hyde Park', 'Clifton', 'Corryville', 'Northside']

Iterating with Dictionaries¶

  • When iterating through a dictionary, you're actually iterating over the keys:
In [9]:
numbers = {'one': 1, 'two': 2, 'three': 3}

for i in numbers:
    print(i)
one
two
three
  • Similar to enumerate, you can access each key-value pair using .items():
In [10]:
numbers = {'one': 1, 'two': 2, 'three': 3}

for key, value in numbers.items():
    print(key, "-", value)
one - 1
two - 2
three - 3

Iterating Over a Series¶

  • Recall that a DataFrame column/row is a Series -- a one-dimensional sequence
  • Consequently, a Series can be iterated through
  • Let's start by loading a DataFrame
In [11]:
import pandas as pd
flights_df = pd.read_csv('../data/flights.csv')
  • We can iterate over certain variables to perform common tasks
  • Assume we wanted to convert all time-related variables from minutes to hours:
In [12]:
flights_df[['dep_delay', 'arr_delay', 'air_time']].head(3)
Out[12]:
dep_delay arr_delay air_time
0 2.0 11.0 227.0
1 4.0 20.0 227.0
2 2.0 33.0 160.0
  • We can loop through the variable names and use pandas subsetting and column syntax to manipulate and overwrite the variables
In [13]:
time_variables = ['dep_delay', 'arr_delay', 'air_time']

for variable in time_variables:
    flights_df[variable] = flights_df[variable] / 60
In [14]:
flights_df[['dep_delay', 'arr_delay', 'air_time']].head(3)
Out[14]:
dep_delay arr_delay air_time
0 0.033333 0.183333 3.783333
1 0.066667 0.333333 3.783333
2 0.033333 0.550000 2.666667

Your Turn¶

  1. Fill in the blanks to print the square of all of the numbers in the list.
for ______ in [0, 2, 4, 6, 8, 10]:
    print(element ** ______)
  1. What is the following code doing?
import numpy as np

for column in flights_df.columns:
    if flights_df[column].dtype != np.float64 and flights_df[column].dtype != np.int64:
        flights_df[column] = flights_df[column].str.lower()

Iterating Until a Condition is Met¶

  • We've seen that we can iterate N times or through/over objects
  • But we can also iterate until a condition is met -- we'll incorporate our knowledge of conditionals here
  • There are two distinct ways of doing this: the break statement and the while loop

break statement¶

  • The break statement can be used to exit a loop at any time
In [15]:
for number in range(10):
    if number == 5:
        break
    print(number)
0
1
2
3
4
  • In the above example, the for loop breaks during the 5th iteration -- when number is equal to 5
  • Note that the code in the rest of that iteration is not run -- this is evidenced by 5 not be printed

while Loops¶

  • While break can be included in complex loops with a lot of conditions, the while loop can be used during simple tasks
In [16]:
number = 1
while number < 5:
    print(number)
    number = number + 1
1
2
3
4
  • While they're convenient in iterating until a condition is met, while loops do require control of an iterator or conditional variable

Your Turn¶

  1. Rewrite this for loop to use a while loop.

    for number in range(15):
        if number % 2 == 0:
            print(number)
    

Comprehensions¶

Overview¶

  • While not necessary, you will frequently see iteration in the form of comprehensions
  • Comprehensions are condensed versions of loops that are frequently represented in a single line
  • They also automatically place their result in a commonly used data structure
    • List comprehensions place their result in lists
    • Dictionary comprehensions place their result in dictionaries
    • There are others, but we won't highlight them here

Using Comprehensions¶

  • Recall our loop to count to N, and let's put it in a list:
In [17]:
number_list_loop = []
for number in range(5):
    number_list_loop.append(number)
  • We can represent this as a list comprehension:
In [18]:
number_list_comprehension = [number for number in range(5)]
  • We can see that they're equal despite the comprehension being far simpler:
In [19]:
number_list_loop == number_list_comprehension
Out[19]:
True
  • In another example, we can apply a method to alter the values
In [20]:
neighborhoods = [
    neighborhood.title()
    for neighborhood
    in ['oakley', 'hyde park', 'clifton', 'corryville', 'northside']
]
In [21]:
neighborhoods
Out[21]:
['Oakley', 'Hyde Park', 'Clifton', 'Corryville', 'Northside']
  • Comprehensions can take a while to...cough, cough...comprehend
  • But just think of them as backward for loops
  • Basic example:
# syntax of for loop
for i in sequence:
  expression

# syntax for a list comprehension
[expression for i in sequence]
  • With a conditional:
# syntax of for loop
for i in sequence:
  if i == condition:  
    expression

# syntax for a list comprehension
[expression for i in sequence if i == condition]

Dictionary Comprehension¶

  • Dictionary comprehensions use a similar syntax as list comprehensions
  • The output is, naturally, a dictionary
  • Let's create a dictionary where the values are altered versions of the keys
In [22]:
neighborhoods = [
    'oakley', 'hyde park', 'clifton', 'corryville', 'northside'
]

neighborhoods_loop = {}
for name in neighborhoods:
    neighborhoods_loop[name] = name.title()
In [23]:
neighborhoods_loop
Out[23]:
{'oakley': 'Oakley',
 'hyde park': 'Hyde Park',
 'clifton': 'Clifton',
 'corryville': 'Corryville',
 'northside': 'Northside'}
  • Now, let's re-write this as a comprehension:
In [24]:
neighborhoods = [
    'oakley', 'hyde park', 'clifton', 'corryville', 'northside'
]

neighborhoods_comprehension = {
    name: name.title()
    for name in neighborhoods
}
In [25]:
neighborhoods_comprehension
Out[25]:
{'oakley': 'Oakley',
 'hyde park': 'Hyde Park',
 'clifton': 'Clifton',
 'corryville': 'Corryville',
 'northside': 'Northside'}
In [26]:
neighborhoods_loop == neighborhoods_comprehension
Out[26]:
True
  • Basic example:
# syntax of for loop
for i in sequence:
    expression

# syntax of dictionary comprehension
{key: expression for i in sequence}

Questions¶

Are there questions before moving on?