DS2000 (Spring 2019, NCH) :: Lecture 3a

0. Administrivia

  1. Due Friday @ 9pm: HW2 (submit via Blackboard)

1. Challenges with for

The basic idea of the for loop is for you to be able to execute some block of code for each element of a list/sequence. Let's now expand what we can do with that idea...

Challenge 1: how do we do something X times (where X might be large?)

In [2]:
num_times = 20

# we need a list or sequence of length 100
long_string = "a" * num_times
long_list = [1] * num_times

# _ is our way of saying we don't
# actually care what is in the list
for _ in long_string: # could also have been long_list
    print("I will practice programming everyday!")
    
# In retrospect, we made something big and didn't actually care about
# what we made... that seems sad & wasteful :(
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!

Challenge 2: how do we output how many times we've done something?

In [3]:
num_times = 20

count = 0
for _ in ("a"*num_times):
    print("{}. I will practice programming everyday!".format(count+1))
    count = count + 1
1. I will practice programming everyday!
2. I will practice programming everyday!
3. I will practice programming everyday!
4. I will practice programming everyday!
5. I will practice programming everyday!
6. I will practice programming everyday!
7. I will practice programming everyday!
8. I will practice programming everyday!
9. I will practice programming everyday!
10. I will practice programming everyday!
11. I will practice programming everyday!
12. I will practice programming everyday!
13. I will practice programming everyday!
14. I will practice programming everyday!
15. I will practice programming everyday!
16. I will practice programming everyday!
17. I will practice programming everyday!
18. I will practice programming everyday!
19. I will practice programming everyday!
20. I will practice programming everyday!

Challenge 3: how do we systematically skip elements in a list?

In [4]:
mylist = ['important', 'not', 'really important', 'so not important', '!!!', ';)']
# so...
# 0 = keep
# 1 = don't keep
# 2 = keep
# 3 = don't keep
# 4 = keep
# 5 = don't keep
# pattern?

count = 0
for element in mylist:
    if count % 2 == 0:
        print(element)
    count += 1
important
really important
!!!

Challenge 4: how do we work with multiple lists at once!?

In [5]:
mynames = ["alice", "bob", "carol"]
myages = [28, 44, 57]
myfaves = ["programming", "traveling", "hugging pandas"]

count = 0
for name in mynames:
    print("{} is {} years old and really likes {}".format(name, myages[count], myfaves[count]))
    count += 1
alice is 28 years old and really likes programming
bob is 44 years old and really likes traveling
carol is 57 years old and really likes hugging pandas

2. Some Better Solutions with range

The range function "creates" a numerical list on-the-fly based upon arguments you supply, including the starting value (inclusive), the ending value (exclusive), and the step we take between each value.

Note: it doesn't really create the underlying list unless you ask (e.g., via the list function), but acts this way for purposes of a for loop (so just as good, but not as wasteful).

In [6]:
# Only requirement is upper bound: assumes lower=0, step=1
print(list(range(5)))

# Starts at 1, upper bound is 5; assumes step=1
print(list(range(1, 5)))

# No assumptions made :)
print(list(range(1, 5, 2)))
[0, 1, 2, 3, 4]
[1, 2, 3, 4]
[1, 3]

So back to Challenge 1 (doing something X times)...

In [7]:
num_times = 20

for _ in range(num_times):
    print("I will practice programming everyday!")
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!
I will practice programming everyday!

And Challenge 2 (how many times we've done something)...

In [8]:
num_times = 20

# Note, we now care about which element we're on...
# it takes the place of our counter!
for count in range(num_times):
    print("{}. I will practice programming everyday!".format(count+1))
1. I will practice programming everyday!
2. I will practice programming everyday!
3. I will practice programming everyday!
4. I will practice programming everyday!
5. I will practice programming everyday!
6. I will practice programming everyday!
7. I will practice programming everyday!
8. I will practice programming everyday!
9. I will practice programming everyday!
10. I will practice programming everyday!
11. I will practice programming everyday!
12. I will practice programming everyday!
13. I will practice programming everyday!
14. I will practice programming everyday!
15. I will practice programming everyday!
16. I will practice programming everyday!
17. I will practice programming everyday!
18. I will practice programming everyday!
19. I will practice programming everyday!
20. I will practice programming everyday!

And Challenge 3 (systematic skipping)...

In [9]:
mylist = ['important', 'not', 'really important', 'so not important', '!!!', ';)']

# First step: what do we supply to range when using a list?
# Answer: range(len(mylist))

for iteration in range(len(mylist)):
    print("all: " + mylist[iteration])

print()
    
# So now on to skipping
# Option 1: if
for iteration in range(len(mylist)):
    if iteration % 2 == 0:
        print("keep 1: " + mylist[iteration])

print()
        
# Option 2: if the pattern is easy, use range!
for iteration in range(0, len(mylist), 2):
    print("keep 2: " + mylist[iteration])
all: important
all: not
all: really important
all: so not important
all: !!!
all: ;)

keep 1: important
keep 1: really important
keep 1: !!!

keep 2: important
keep 2: really important
keep 2: !!!

And Challenge 4 (multiple lists)...

In [10]:
mynames = ["alice", "bob", "carol"]
myages = [28, 44, 57]
myfaves = ["programming", "traveling", "hugging pandas"]

for iteration in range(len(mynames)):
    print("{} is {} years old and really likes {}".format(name, myages[iteration], myfaves[iteration]))
carol is 28 years old and really likes programming
carol is 44 years old and really likes traveling
carol is 57 years old and really likes hugging pandas

2a. A Couple Other Tools: enumerate and zip

The enumerate function allows you to loop over the index and value of list/sequence elements at the same time...

In [11]:
mylist = ['important', 'not', 'really important', 'so not important', '!!!', ';)']

for iteration, element in enumerate(mylist):
    print("Index={}, Value={}".format(iteration, element))

print()

for charnum, character in enumerate("word"):
    print("Index={}, Value={}".format(charnum, character))
Index=0, Value=important
Index=1, Value=not
Index=2, Value=really important
Index=3, Value=so not important
Index=4, Value=!!!
Index=5, Value=;)

Index=0, Value=w
Index=1, Value=o
Index=2, Value=r
Index=3, Value=d

So let's revisit Challenge 3 for yet another option...

In [12]:
for iteration, element in enumerate(mylist):
    if iteration % 2 == 0:
        print(element)
important
really important
!!!

The zip function allows you to loop over multiple lists in parallel...

In [13]:
mynames = ["alice", "bob", "carol"]
myages = [28, 44, 57]
myfaves = ["programming", "traveling", "hugging pandas"]

for name, age, fave in zip(mynames, myages, myfaves):
    print("{} is {} years old and really likes {}".format(name, age, fave))
alice is 28 years old and really likes programming
bob is 44 years old and really likes traveling
carol is 57 years old and really likes hugging pandas

3. A Different Kind of Looping: while

The for loop is super useful when you are performing the same operation for a known duration/sequence.

But what about when you do NOT know ahead of time when to stop, such as when validating input or waiting for a certain condition to hold...

In [14]:
joke = ""
count = 0

while joke != "quit":
    joke = input("Please tell me a joke: ")
    count += 1
    print("Ha" * count)

print("Wow, my ribs hurt... ;)")
Please tell me a joke: knock knock
Ha
Please tell me a joke: foo bar
HaHa
Please tell me a joke: you must be a computer...
HaHaHa
Please tell me a joke: and/or have a bad sense of humor...
HaHaHaHa
Please tell me a joke: don't care, this makes me feel better about my sense of humor :)
HaHaHaHaHa
Please tell me a joke: wow, mean...
HaHaHaHaHaHa
Please tell me a joke: quit
HaHaHaHaHaHaHa
Wow, my ribs hurt... ;)

Another example is an iterative algorithm, where each loop iteration gets closer to an answer (but you might not want to wait 5 years for an answer!)...

In [15]:
# Adapted from Text (8.6)
# Let's approximate the square root of a number, n

n = 289
max_iterations = 10

count = 1
approx = 0.5 * n
better = 0.5 * (approx + n/approx)
while (better != approx) and (count < max_iterations):
    approx = better
    better = 0.5 * (approx + n/approx)
    count += 1

print("After {} iterations, sqrt({})={}".format(count, n, approx))
After 9 iterations, sqrt(289)=17.0

Note the similarity of syntax/interpretation with an if statement -- but whereas if checks the condition (and potentially executes the block) once, while continues as long as the condition holds.