Control flow - while loop

Download exercises zip

Browse online files

Let’s see how to repeat instructions by executing them inside while loops.

The main feature of while loop is allowing to explicitly control when the loop should end. Typically, such loops are used when we must iterate on a sequence of which we don’t know the dimension, or it can vary over time, or several conditions might determine the cycle stop.

What to do

  1. Unzip exercises zip in a folder, you should obtain something like this:

control-flow
    flow1-if.ipynb
    flow1-if-sol.ipynb
    flow2-for.ipynb
    flow2-for-sol.ipynb
    flow3-while.ipynb
    flow3-while-sol.ipynb
    jupman.py

WARNING: to correctly visualize the notebook, it MUST be in an unzipped folder !

  1. open Jupyter Notebook from that folder. Two things should open, first a console and then a browser. The browser should show a file list: navigate the list and open the notebook flow3-while.ipynb

  2. Go on reading the exercises file, sometimes you will find paragraphs marked Exercises graded from ✪ to ✪✪✪✪ which will ask to write Python commands in the following cells.

Shortcut keys:

  • to execute Python code inside a Jupyter cell, press Control + Enter

  • to execute Python code inside a Jupyter cell AND select next cell, press Shift + Enter

  • to execute Python code inside a Jupyter cell AND a create a new cell aftwerwards, press Alt + Enter

  • If the notebooks look stuck, try to select Kernel -> Restart

Introduction

A while cycle is a code block which is executed when a certain boolean condition is verified. The code block is repeatedly executed as long as the condition is true.

Let’s see an example:

[2]:
i = 1

while i < 4:
    print('Counted', i)
    i += 1

print('Loop is over!')
Counted 1
Counted 2
Counted 3
Loop is over!

In the example, the boolean condition is

i < 4

the block to repeatedly executed is

print('Counted', i)
i += 1

Like any Python code blocks, the block is indented with spaces (usually 4).

Have a better look at the execution in Python Tutor and read the following comment.

[3]:
# WARNING: FOR PYTHON TUTOR TO WORK, REMEMBER TO EXECUTE THIS CELL with Shift+Enter
#          (it's sufficient to execute it only once)

import jupman
[4]:
i = 1
while i < 4:
    print('Counted', i)
    i += 1

print('Loop is over !')

jupman.pytut()
Counted 1
Counted 2
Counted 3
Loop is over !
[4]:

In the example we used a variable we called i and we initialized it to zero.

At the beginning of the cycle i is valued 1, so the boolean expression i < 4 is evaluated as True. Since it’s True, execution continues inside the block with the print and finally MODIFIES i by incrementing i += 1.

Now the execution goes to while row, and condition i < 4 is evaluated again. At this second iteration i is valued 2, so the boolean expression i < 4 is again evaluated to True and the execution remains inside the block. A new print is done and i gets incremented.

Another loop is done until i is valued 4. A that point i < 4 produces False so in that moment execution exits the while block and goes on with the commands at the same indentation level as the while

Terminating while

When we have a while cycle, typically sooner or later we want it to terminate (programs which hang aren’t users’ favourites …). To guarantee termination, we need:

  1. initializing a variable outside the cycle

  2. a condition after the while command which evaluates that variable (and optionally other things)

  3. at least one instruction in the internal block which MODIFIES the variable, so that sooner or later is going to satisfy condition 2

If any of these points is omitted, we will have problems. Let’s try forgetting them on purpose:

Error 1: omit initialization. As in those cases in Python where we forgot to initialize a variable (let’s try j in this case), the execution is interrupted as soon we try using the variable:

print("About to enter the cycle ..")
while j < 4:
    print('Counted', j)
    j += 1

print('Loop is over !')
About to enter the cycle ..
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-277-3f311955204d> in <module>()
      1 print("About to enter the cycle ..")
----> 2 while j < 4:
      3     print('Counted', j)
      4     j += 1
      5

NameError: name 'j' is not defined

Error 2: omit using the variable in the condition. If we forget to evaluate the variable, for example using another one by mistake (say x), the loop will never stop:

i = 1
x = 1
print('About to enter the cycle ..')
while x < 4:   # evalutes x instead of i
    print('Counted', i)
    i += 1

print('Loop is over !')
About to enter the cycle ..
Counted 1
Counted 2
Counted 3
Counted 4
Counted 5
Counted 6
.
.

Error 3: Omit to MODIFY the variable in the internal block. If we forget to place at least one instruction which MODIFIES the variable used in the condition, whenever the condition is evaluated it will always produce the same boolean value False preventing a cycle exit:

i = 1
print('About to enter the cycle ..')
while i < 4:
    print('Counted', i)

print('Loop is over !')
About to enter the cycle ..
Counted 1
Counted 1
Counted 1
Counted 1
Counted 1
.
.

Non terminating while

QUESTION: Can you imagine a program which never terminates?

Show answer

Questions

QUESTION: Look at the following code fragments , and for each try guessing the result it produces (or if it gives an error):

  1. i = 0
    while i < 3:
    print(i)
    
  2. k = 0
    while k < 5:
        print(k)
        k + 1
    
  3. i = 0
    while i < 3:
        print(i)
    i += 1
    
  4. i = 0
    while False:
        print(i)
        i += 1
    print('Done !')
    
  5. i = 0
    while i < 3:
        print(i)
        i += 1
    
  6. k = 0
    while k < 2
        print(i)
        k += 1
    
  7. i = 0
    while i < 3:
        print('GAM')
        i = i + 1
    
  8. while zanza < 2
        print('ZANZA')
        zanza += 1
    
  9. i = 0
    while False:
        print(i)
        i = i + 1
    print('DARK')
    
  10. i = 0
    while True:
        print(i)
        i = i + 1
    print('LIGHT')
    
  11. while 2 + 3:
        print('z')
    print('')
    
  12. i = 10
    while i > 0:
        if i > 5:
            print(i)
            i -= 1
    print('WAM')
    
  13. i = 10
    while i > 0:
        if i > 5:
            print(i)
        i -= 1
    print('MAW')
    
  14. import random
    x = 0
    while  x < 7:
        x = random.randint(1,10)
        print(x)
    
    print('LUCK')
    
  15. x,y = 0,0
    while x + y < 4:
        x += 1
        y += 1
        print(x,y)
    
  16. x,y = 0,3
    while x < y:
        print(x,y)
        x += 1
        y -= 1
    

Esercises - introduction

Exercise - printeven

✪ Write some code to print all the odd numbers from 1 to k in a while cycle

  • for k<1 prints nothing

Example - given:

k = 5

after your code it must print:

1
3
5
Show solution
[5]:
k = 5   # 1 3 5
#k = 1  # 1
#k = 0  # no print

# write here


1
3
5

Exercise - average

✪ Write some code that given a list numbers, calculates the average of values using a while and then prints it.

  • if the list is not empty, the average is supposed to be 0.0

  • DO NOT use the function sum

  • DO NOT create variables called sum (would violate the V COMMANDMENT: you shall never ever redefine system functions)

Example - given:

numbers = [8,6,5,9]

prints

7.0
Show solution
[6]:
numbers = [8,6,5,9] # 7.0
#numbers = [3,1,2]  # 2.0
#numbers = []       # 0

# write here


7.0

break and continue commands

For getting even more control on cycle execution we can use the commands break and continue

NOTE: Use them sparingly!

When there is a lot of code in the cycle it’s easy to ‘forget’ about their presence and introduce hard-to-discover bugs. On the other hand, in some selected cases these commands may increase code readability, so as everything use your judgement.

Terminate with a break

The scheme we’ve seen to have a terminating while is the recommended one, but if we have a condition which does NOT evaluate the variable we are incrementing (like for example the constant expression True), as an alternative to immediatly exit the cycle we can use the command break:

[7]:
i = 1
while True:

    print('Counted', i)

    if i > 3:
        print('break! Exiting the loop!')
        break
        print('After the break')

    i += 1

print('Loop is over !')
Counted 1
Counted 2
Counted 3
Counted 4
break! Exiting the loop!
Loop is over !

Note After the break is not shown.

Jumping with continue

We can bring the execution immediately to the next iteration by calling continue, which directly jumps to the condition check without executing the instructions after the continue.

WARNING: continue instructions if used carelessly can cause infinite loops !

When using continue ensure it doesn’t jump the instriction which modifies the variable used in the termination condition (or it doesn’t jump a break needed for exiting the cycle)!

To avoid problems here we incremented i before the if with a continue:

[8]:
i = 1
while i < 5:
    print('Counted', i)

    i += 1

    if i % 2 == 1:
        print('continue, jumping to condition check')
        continue
        print('After the continue')

    print('arrived till the end')

print('Loop is over !')
Counted 1
arrived till the end
Counted 2
continue, jumping to condition check
Counted 3
arrived till the end
Counted 4
continue, jumping to condition check
Loop is over !

Let’s try combining break and continue, and see what happens in Python Tutor:

[9]:
i = 1
while i < 5:
    print('Counted', i)
    if i > 3:
        print('break! Exiting the cycle!')
        break
        print('After the break')
    i += 1
    if i % 2 == 1:
        print('continue, jumping to next condition check')
        continue
        print('After the continue')
    print('arrived till the end')

print('Loop is over !')

jupman.pytut()
Counted 1
arrived till the end
Counted 2
continue, jumping to next condition check
Counted 3
arrived till the end
Counted 4
break! Exiting the cycle!
Loop is over !
[9]:

Questions about break and continue

QUESTION: Look at the following code fragments , and for each try guessing the result it produces (or if it gives an error):

  1. i = 1
    while i < 4:
        print('Counted', i)
        i += 1
        continue
    
    print('Loop is over !')
    
  2. i = 1
    while i < 4:
        print('Counted', i)
        continue
        i += 1
    
    print('Loop is over !')
    
  3. i = 3
    while i > 0:
        print('Counted', i)
        if i == 2:
            print('continue, jumping to condition check')
            continue
        i -= 1
        print('arrived till the end')
    
    print('Loop is over !')
    
  4. i = 0
    while True:
        i += 1
        print(i)
        if i > 3:
            break
    
    print('BONG')
    
  5. i = 0
    while True:
        if i < 3:
            continue
        else:
            break
        i += 1
    
    print('ZONG')
    
  6. i = 0
    while True:
        i += 1
        if i < 3:
            continue
        else:
            break
    
    print('ZANG')
    

Exercise - findchar

✪✪ Write some code that using a while searches the character list la for a character specified in car variable. As soon as the FIRST character occurrence is found, it stops and prints the index where it was found.

  • if it doesn’t find the character, prints a Not found message.

Example 1 - given:

car = 'z'
la = ['b','a','f','g','z','h','z','r']

after your code it must print:

Found first z at index 4

Example 2 - given:

car = 'z'
la = ['b','a','f','g','h','r']

must print:

Didn't find z
Show solution
[10]:

car = 'z'

#      0   1   2   3   4   5   6   7
la = ['b','a','f','g','z','h','z','r']   # Found first z at index 4
#la = ['b','a','f','g','h','r']          # Didn't find z


# write here


Found first z at index 4

Questions - Are they equivalent?

Look at the following code fragments: each contains two parts, A and B. For each value of the variables they depend on, try guessing whether part A will print exactly the same result printed by code in part B

  • FIRST think about the answer

  • THEN try executing with each of the values of suggested variables

Are they equivalent? - BORG

print('A:')
while True:
    print('BORG')
    break

print('\nB:')
while False:
    pass
print('BORG')

Are they equivalent? - until 3

print('A:')
x = 0
while x < 3:
    print(x)
    x += 1

print('\nB:')
x = 1
while x <= 3:
    print(x-1)
    x += 1

Are they equivalent? - by chance

Remember randint(a, b) gives back a random integer N such that a <= N <= b

print('A:')
x = 0
while x < 3:
    x += 1
print(x)

print('\nB:')
x = 0
import random
while x != 3:
    x = random.randint(1,5)
print(x)

Are they equivalent? - until six

print('A:')
i = 0
while i < 3:
    print(i)
    i += 1
while i < 6:
    print(i)
    i += 1

print('\nB:')
i = 0
while i < 6:
    print(i)
    i += 1

Are they equivalent? - countdown 1

print('A:')
i = 2
print(i)
while i > 0:
    i -= 1
    print(i)

print('\nB:')
i = 2
while i > 0:
    print(i)
    i -= 1

Are they equivalent? - countdown 2

print('A:')
i = 2
print(i)
while i > 0:
    i -= 1
    print(i)

print('\nB:')
i = 2
while i > 0:
    print(i)
    i -= 1
print(i)

Are they equivalent? - sorcery

print('A:')
s = 'sorcery'
i = 0
while s[i] != 'g':
    i += 1
print(s[i:])

print('B:')
s = 'sorcery'
i = len(s)
while s[i] != 'g':
    i -= 1
print(s[i:])

Are they equivalent? - ping pong

print('A:')
ping,pong = 0,3
while ping < 3 or pong > 0:
    print(ping,pong)
    ping += 1
    pong -= 1

print('\nB:')
ping,pong = 0,3
while not(ping >= 3 and pong <= 0):
    print(ping,pong)
    ping += 1
    pong -= 1

Are they equivalent? - zanna

print('A:')
n,i,s = 0,0,'zanna'
while i < len(s):
    if s[i] == 'n':
        n += 1
    i += 1
print(n)

print('\nB:')
n,i,s = 0,0,'zanna'
while i < len(s):
    i += 1
    if s[i-1] == 'n':
        n += 1
print(n)

Are they equivalent? - pasticcio

print('A:')
c,i,s = 0,0,'pasticcio'
while i < len(s):
    if s[i] == 'c':
        c += 1
    i += 1
print(c)

print('\nB:')
no,k,s = 0,0,'pasticcio'
while k < len(s):
    if s[k] != 'c':
        no += 1
    else:
        k += 1
print(len(s) - no)

Exercises - counters

Exercise - don’t break 1

✪ Look at the following code, and write in the following cell some code which produces the same result with a while and without using break

[11]:
x = 3
while True:
    print(x)
    if x == 0:
        break
    x -= 1
3
2
1
0
Show solution
[12]:
x = 3

# write here


3
2
1
0

Exercise - don’t break 2

✪ Look at the following code, and write in the following cell some code which produces the same result with a while and without using break

[13]:
la = [2,3,7,5,6]
k = 7   # 2 3 7
#k = 5  # 2 3 7 5 6
#k = 13 # 2 3 7 5 6

i = 0
while True:
    print(la[i])
    if i >= len(la)-1 or la[i] == k:
        break
    else:
        i += 1
2
3
7
Show solution
[14]:
la = [2,3,7,5,6]
k = 7   # 2 3 7
#k = 6  # 2 3 7 5 6
#k = 13 # 2 3 7 5 6

i = 0

# write here


2
3
7

Exercise - Give me a break

✪ Look at the following code, and write in the next cell some code which produces the same result with a while this time using a break

[15]:

x,y = 1,5    # (1,5)  (2,4)
#x,y = 2,8   # (2, 8) (3, 7) (4, 6)

while x < y or x == 4:
    print((x,y))
    x += 1
    y -= 1
(1, 5)
(2, 4)
Show solution
[16]:
x,y = 1,5    # (1,5)  (2,4)
#x,y = 2,8   # (2, 8) (3, 7) (4, 6)

# write here


(1, 5)
(2, 4)

Exercise - paperboard

✪ Prints integer numbers from 0 to k INCLUDED using a while, and for each number prints to its side one among the strings 'PA', 'PER' and 'BOARD' alternating them

Ex - for k=8 prints

0 PA
1 PER
2 BOARD
3 PA
4 PER
5 BOARD
6 PA
7 PER
8 BOARD
Show solution
[17]:
k = 8

# write here


0 PA
1 PER
2 BOARD
3 PA
4 PER
5 BOARD
6 PA
7 PER
8 BOARD

Exercise - until ten

✪ Given two numbers x and y, write some code with a while which prints and increments the numbers, stopping as soon as one of them reaches ten.

x,y = 5,7

after your code it must result:

5 7
6 8
7 9
8 10
Show solution
[18]:
x,y = 5,7
#x,y = 8,4

# write here


5 7
6 8
7 9
8 10

Exercise - cccc

✪ Write some code using a while which given a number y, prints y rows containing the character c as many times as the row number.

Example - given:

y = 4

Prints:

c
cc
ccc
cccc
Show solution
[19]:

y = 4

# write here



c
cc
ccc
cccc

Exercise - converge

✪ Given two numbers x and k, using a while modify and print x until it reaches k included

  • NOTE: k can either be greater or lesser than x, you must handle both cases

Example 1 - given:

x,k = 3,5

prints:

3
4
5

Example 2 - given:

x,k = 6,2

prints:

6
5
4
3
2
Show solution
[20]:

x,k = 3,5    # 3 4 5
#x,k = 6,2   # 6 5 4 3 2
#x,k = 4,4   # 4

# write here


3
4
5

Exercise - wow

✪ Given a list of strings la, write some code that searches inside the list for the first occurrence of a string beginning with the character 2 (for example 'wow'. As soon as it is found, the program stops and prints Found wow. Otherwise, prints Not found! Use a while cycle.

Example 1 - given:

la = ['a','d','g','wow','f','wonder','r']

Prints:

examined a
examined d
examined g
Found wow

Example 2 - given:

la = ['d','v','q','c','e']

Prints:

examined d
examined v
examined q
examined c
examined e
Not found!
Show solution
[21]:
la = ['a','d','g','wow','f','wonder','r']      # a d g Found wow
#la = ['a','d','g','f','wonder','r', 'woman']  # a d g f Found wonder
#la = ['d','v','q','c','e']                    # d v q c e Not found!

# write here


examined a
examined d
examined g
Found wow

Exercise - Wild West

✪✪ The two outlaws Carson and Butch agreed to bury a treasure in the jolly town of Tombstone, ma now each of them wants to take back the treasure without sharing anything with the partner.

  • For arriving to the treasure there is a road from Santa Fe until Tombstone which we represent as a list of strings

  • we use two indexes butch and carson to represent where the outlaws are on the road

  • each outlaw starts from a different town

  • at each turn Carson moves of one city

  • at each turn Butch moves of two cities, because he has a fast Mustang horse

Write some code which prints the run and terminates as soon as one them arrives to the last city, telling who got the treasure.

  • In the case both outlaws arrive to the last city at the same time, prints Final duel in Tombstone!

  • your code must work for any road and initial position carson and butch

Example - 1 given:

#             0         1          2           3            4               5
road = ['Santa Fe','Denver','Dodge City', 'Silverton', 'Agua Caliente', 'Tombstone']
carson,butch  = 3, 0

it must print:

Carson starts from Silverton
Butch starts from Santa Fe
Carson reaches Agua Caliente
Butch reaches Dodge City
Carson reaches Tombstone
Butch reaches Agua Caliente

Carson takes the treasure in  Tombstone !

Example 2 - given:

#            0         1          2           3              4               5
road = ['Santa Fe','Denver','Dodge City', 'Silverton', 'Agua Caliente', 'Tombstone']
carson,butch  = 3, 2

it must print:

Carson starts from Silverton
Butch starts from Dodge City
Carson reaches Agua Caliente
Butch reaches Agua Caliente
Carson reaches Tombstone
Butch reaches Tombstone

Final duel in  Tombstone !
Show solution
[22]:
#           0          1         2              3              4              5
road = ['Santa Fe','Denver','Dodge City', 'Silverton', 'Agua Caliente', 'Tombstone']

carson,butch  = 3, 0    #  Carson takes the treasure in Tombstone !
#carson,butch  = 0, 0   #  Butch takes the treasure in Tombstone !
#carson,butch  = 3, 2   #  Final duel in Tombstone !

# write here


Carson starts from Silverton
Butch starts from Santa Fe
Carson reaches Agua Caliente
Butch reaches Dodge City
Carson reaches Tombstone
Butch reaches Agua Caliente

Carson takes the treasure in  Tombstone !

Modifying sequences

In the tutorial on for loops we’ve seen an important warning we repeat here:

X COMMANDMENT: You shall never ever add or remove elements from a sequence you are iterating with a for !

Falling into such temptations would produce totally unpredictable behaviours (do you know the expression pulling the rug out from under your feet ? )

If you really need to remove elements from a sequence you are iterating, use a while cycle or duplicate first a copy of the original sequence.

Note the advice is only about for cycles. In case of necessity, at the end suggests to adopt while loops. Let’s see when and how ot use them.

Stack - Drawing from a card deck

Suppose having a deck of cards which we represent as a list of strings, and we want to draw all the cards, reading them one by one.

We can write a while that as long as the deck contains cards, keeps removing cards from the top with the pop method and prints their name. Remember pop MODIFIES the list by removing the last element AND gives back the element as call result, which we can save in a variable we will call card:

[23]:
deck = ['3 hearts',   # <---- bottom
        '2 spades',
        '9 hearts',
        '5 diamonds',
        '8 clubs']    # <---- top

while len(deck) > 0:
    card = deck.pop()
    print('Drawn', card)

print('No more cards!')

jupman.pytut()
Drawn 8 clubs
Drawn 5 diamonds
Drawn 9 hearts
Drawn 2 spades
Drawn 3 hearts
No more cards!
[23]:

Looking at the code, we can notice that:

  1. the variable deck is initialized

  2. we verify that deck dimension is greater than zero

  3. at each step the list deck is MODIFIED by reducing its dimension

  4. it returns to step 2

The first three points are the conditions which guarantee the while loop will sooner or later actually terminate.

Stack - Drawing until condition

Suppose now to continue drawing cards until we find a heart suit. The situation is more complicated, because now the cycle can terminate in two ways:

  1. we find hearts, and interrupt the search

  2. there aren’t heart cards, and the deck is exhausted

In any case, in the end we must tell the user a result. To do so, it’s convenient initializing card at the beginning like an empty string for handling the case when no hearts cards are found (or the deck is empty).

Let’s try a first implementation which uses an internal if to verify whether we have found hearts, and in that case exits with a break command.

  • Try executing the code by uncomment the second deck which has no hearts cards, and look at the different execution.

[24]:
deck = ['3 hearts','2 spades','9 hearts','5 diamonds','8 clubs']
#deck = ['8 spades','2 spades','5 diamonds','4 clubs']   # no hearts!

card = ''
while len(deck) > 0:
    card = deck.pop()
    print('Drawn', card)
    if 'hearts' in card:
        break

if 'hearts' in card:
    print('Found hearts!')
else:
    print("Didn't find hearts!")

jupman.pytut()
Drawn 8 clubs
Drawn 5 diamonds
Drawn 9 hearts
Found hearts!
[24]:

Exercise - Don’t break my heart

✪ Write some code which solves the same previous problem:

  • this time DO NOT use break

  • ensure the code works with a deck without hearts, and also with an empty deck

  • HINT: put a multiple condition in the while

Show solution
[25]:
deck = ['3 hearts','2 spades','9 hearts','5 diamonds','8 clubs']
#deck = ['8 spades','2 spades','5 diamonds','4 clubs']   # no hearts!
#deck = []  #  no hearts !

card = ''

# write here


Drawn 8 clubs
Drawn 5 diamonds
Drawn 9 hearts
Found hearts!

Questions - what happens?

QUESTION: Look at the following code fragments , and for each try guessing the result it produces (or if it gives an error):

  1. while []:
        print('z')
    print('BIG')
    
  2. while ['a']:
        print('z')
    print('BUG')
    
  3. la = []
    while len(la) < 3:
        la.append('x')
    print(la)
    
  4. la = ['x','y','z']
    while len(la) > 0:
        print(la.pop())
    
  5. la = ['x','y','z']
    while la:
        print(la.pop(0))
    
  6. la = [4,5,8,10]
    while la.pop() % 2 == 0:
        print(la)
    

Questions - are they equivalent?

Look at the following code fragments: each contains two parts, A and B. For each value of the variables they depend on, try guessing whether part A will print exactly the same result printed by code in part B

  • FIRST think about the answer

  • THEN try executing with each of the values of suggested variables

Are they equivalent? - train

print('A:')
la = ['t','r','a','i','n']
while len(la) > 0:
    print(la.pop())

print('\nB:')
la = ['t','r','a','i','n']
la.reverse()
while len(la) > 0:
    print(la.pop(0))

Are they equivalent? - append nx

print('A:')
x,n,la = 2,0,[]
while x not in la:
    la.append(n)
    n += 1
print(la)

print('\nB:')
x,la = 2,[]
while len(la) < 3:
    la.append(x)
    x += 1
print(la)

Exercises - stack

Exercise - break sum

✪ Look at the following code, and rewrite it in the following cell as while

  • this time use command break

[26]:
lst = []
i = 0
k = 10
while sum(lst) < k:
    lst.append(i)
    i += 1
    print(lst)
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
Show solution
[27]:
lst = []
i = 0

# write here


[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]

Exercise - travelbook

✪✪ Suppose you visited the attic and found a stack of books, which we represent as a list of strings. Each string is prefixed by a label of one character indicating the category (D for Detective story, T for Travel, H for History)

stack = ['H-Middle Ages',   # <---- bottom
         'T-Australia',
         'T-Scotland',
         'D-Suspects',
         'T-Caribbean']    # <---- top

Since we are passionate about travel books, we want to examine stack one book at a time to transfer books into another pile we call ŧravel, which at the beginning is empty. We start from the top book in stack, and transfer into travel only the books starting with the label T like ('T-Australia')

travel = []

Write some code that produces the following print:

At the beginning:
    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland', 'D-Suspects', 'T-Caribbean']
    travel: []
Taken T-Caribbean
    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland', 'D-Suspects']
    travel: ['T-Caribbean']
Discarded D-Suspects
    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland']
    travel: ['T-Caribbean']
Taken T-Scotland
    stack:   ['H-Middle Ages', 'T-Australia']
    travel: ['T-Caribbean', 'T-Scotland']
Taken T-Australia
    stack:   ['H-Middle Ages']
    travel: ['T-Caribbean', 'T-Scotland', 'T-Australia']
Discarded H-Middle Ages
    stack:   []
    travel: ['T-Caribbean', 'T-Scotland', 'T-Australia']
  • The non-travel books are not interesting and must be discarded

  • Your code must work with any stack list

Show solution
[28]:

stack = ['H-Middle Ages',   # <---- bottom
         'T-Australia',
         'T-Scotland',
         'D-Suspects',
         'T-Caribbean']    # <---- top


travel = []

# write here


At the beginning:
    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland', 'D-Suspects', 'T-Caribbean']
    travel: []
Taken T-Caribbean
    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland', 'D-Suspects']
    travel: ['T-Caribbean']
Discarded D-Suspects
    stack:   ['H-Middle Ages', 'T-Australia', 'T-Scotland']
    travel: ['T-Caribbean']
Taken T-Scotland
    stack:   ['H-Middle Ages', 'T-Australia']
    travel: ['T-Caribbean', 'T-Scotland']
Taken T-Australia
    stack:   ['H-Middle Ages']
    travel: ['T-Caribbean', 'T-Scotland', 'T-Australia']
Discarded H-Middle Ages
    stack:   []
    travel: ['T-Caribbean', 'T-Scotland', 'T-Australia']

Exercise - BANG !

✪✪ There are two stacks of objects right_stack and left_stack which we represent as lists of strings. As a pastime, a cowboy decides to shoot the objects at the top of the stacks, alternating the stack at each shoot. The cowboy is skilled and always hits the target, so each shot decreases a stack.

  • Suppose the objects on top are the ones at the end of the list

  • To keep track of which stack to hit, use a variable shoot holding either 'R' or 'L' character

  • After each shot the cowboy if possible changes the stack , otherwise keeps shooting at the same stack until it’s empty.

  • your code must work for any stack and initial shot

Example - given:

left_stack = ['box','boot','horseshoe','bucket']
right_stack = ['bin','saddle','tin can']
shoot = 'R'

after your code, it must print:

Ready?
   left_stack: ['box', 'boot', 'horseshoe', 'bucket']
  right_stack: ['bin', 'saddle', 'tin can']
BANG! right:  tin can
   left_stack: ['box', 'boot', 'horseshoe', 'bucket']
  right_stack: ['bin', 'saddle']
BANG! left:   bucket
   left_stack: ['box', 'boot', 'horseshoe']
  right_stack: ['bin', 'saddle']
BANG! right:  saddle
   left_stack: ['box', 'boot', 'horseshoe']
  right_stack: ['bin']
BANG! left:   horseshoe
   left_stack: ['box', 'boot']
  right_stack: ['bin']
BANG! right:  bin
   left_stack: ['box', 'boot']
  right_stack: []
BANG! left:   boot
   left_stack: ['box']
  right_stack: []
Nothing to shoot on the right!
   left_stack: ['box']
  right_stack: []
BANG! left:   box
   left_stack: []
  right_stack: []
Show solution
[29]:
left_stack = ['box','boot','horseshoe','bucket']
right_stack = ['bin','saddle','tin can']
shoot = 'R'
#shoot = 'L'
#left_stack = ['bucket', 'box']

# write here


Ready?
   left_stack: ['box', 'boot', 'horseshoe', 'bucket']
  right_stack: ['bin', 'saddle', 'tin can']
BANG! right:  tin can
   left_stack: ['box', 'boot', 'horseshoe', 'bucket']
  right_stack: ['bin', 'saddle']
BANG! left:   bucket
   left_stack: ['box', 'boot', 'horseshoe']
  right_stack: ['bin', 'saddle']
BANG! right:  saddle
   left_stack: ['box', 'boot', 'horseshoe']
  right_stack: ['bin']
BANG! left:   horseshoe
   left_stack: ['box', 'boot']
  right_stack: ['bin']
BANG! right:  bin
   left_stack: ['box', 'boot']
  right_stack: []
BANG! left:   boot
   left_stack: ['box']
  right_stack: []
Nothing to shoot on the right!
   left_stack: ['box']
  right_stack: []
BANG! left:   box
   left_stack: []
  right_stack: []

Exercise - Growing or degrowing?

✪✪ Write some code which given a list la, keeps MODIFYING the list according to this procedure:

  • if the last element is odd (i.e. 7), attaches a new number at the end of the list obtained by multiplying by two the last element (i.e. attaches 14)

  • if the last element is even, removes the last two elements

  • DO NOT create a new list (so no rows starting with la =)

  • WARNING: when we want both grow and degrow the sequence we are considering in a cycle, we must convince ourselves that sooner or later the termination condition will happen, it’s easy to make mistakes and end up with an infinite cycle!

  • HINT: to degrow the list, you can use the pop method

Example - given:

la = [3,5,6,7]

Executing the code, it must print:

 Odd: attaching 14
      la becomes [3, 5, 6, 7, 14]
Even: removing 14
      removing 7
      la becomes [3, 5, 6]
Even: removing 6
      removing 5
      la becomes [3]
 Odd: attaching 6
      la becomes [3, 6]
Even: removing 6
      removing 3
      la becomes []
Done! la is []
Show solution
[30]:
la = [3,5,6,7]

# write here


 Odd: attaching 14
      la becomes [3, 5, 6, 7, 14]
Even: removing 14
      removing 7
      la becomes [3, 5, 6]
Even: removing 6
      removing 5
      la becomes [3]
 Odd: attaching 6
      la becomes [3, 6]
Even: removing 6
      removing 3
      la becomes []
Done! la is []