While loops 1 - introduction
Download exercises zip
Let’s see how to repeat instructions by executing them inside while
loops.
The main feature of while
loop is to allow explicit control when the loop should end. Typically, such loops are used when we must iterate on a sequence we don’t know the dimension of in advance, or the dimension can vary over time, or when several conditions might determine the cycle stop.
What to do
Unzip exercises zip in a folder, you should obtain something like this:
while
while1.ipynb
while1-sol.ipynb
while2-chal.ipynb
jupman.py
WARNING: to correctly visualize the notebook, it MUST be in an unzipped folder !
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
while.ipynb
Go on reading the exercises file, sometimes you will find paragraphs marked Exercises 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
Counting with a while
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 keep executing 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 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:
initializing a variable outside the cycle
a condition after the
while
command which evaluates that variable (and optionally other things)at least one instruction in the internal block which MODIFIES the variable, so that sooner or later condition 2 is going to be satisfied
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 by using a wrong one (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 the cycle from exiting:
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 answerQuestions
QUESTION: Look at the following code fragments , and for each try guessing the result it produces (or if it gives an error):
i = 0 while i < 3: print(i)
k = 0 while k < 5: print(k) k + 1
i = 0 while i < 3: print(i) i += 1
i = 0 while False: print(i) i += 1 print('Done !')
i = 0 while i < 3: print(i) i += 1
k = 0 while k < 2 print(i) k += 1
i = 0 while i < 3: print('GAM') i = i + 1
while zanza < 2 print('ZANZA') zanza += 1
i = 0 while False: print(i) i = i + 1 print('DARK')
i = 0 while True: print(i) i = i + 1 print('LIGHT')
while 2 + 3: print('z') print('')
i = 10 while i > 0: if i > 5: print(i) i -= 1 print('WAM')
i = 10 while i > 0: if i > 5: print(i) i -= 1 print('MAW')
import random x = 0 while x < 7: x = random.randint(1,10) print(x) print('LUCK')
x,y = 0,0 while x + y < 4: x += 1 y += 1 print(x,y)
x,y = 0,3 while x < y: print(x,y) x += 1 y -= 1
Esercises
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
[5]:
k = 5 # 1 3 5
#k = 1 # 1
#k = 0 # no print
# write here
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
[6]:
numbers = [8,6,5,9] # 7.0
#numbers = [3,1,2] # 2.0
#numbers = [] # 0
# write here
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 just seen is the recommended one to properly terminate a while
, 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 we can use the command break
to immediatly exit the cycle:
[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 can cause infinite loops if used carelessly!
When using continue
ensure it doesn’t jump the instruction 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 try guessing for each the result it produces (or if it gives an error):
i = 1 while i < 4: print('Counted', i) i += 1 continue print('Loop is over !')
i = 1 while i < 4: print('Counted', i) continue i += 1 print('Loop is over !')
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 !')
i = 0 while True: i += 1 print(i) if i > 3: break print('BONG')
i = 0 while True: if i < 3: continue else: break i += 1 print('ZONG')
i = 0 while True: i += 1 if i < 3: continue else: break print('ZANG')
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 and write down the expected output
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)
[10]:
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)
A:
2
1
0
B:
2
1
0
Are they equivalent? - sorcery
print('A:')
s = 'sorcery'
i = 0
while s[i] != 'e':
i += 1
print(s[i:])
print('B:')
s = 'sorcery'
i = len(s)
while s[i] != 'e':
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
[12]:
x = 3
# write here
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
[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
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)
[16]:
x,y = 1,5 # (1,5) (2,4)
#x,y = 2,8 # (2, 8) (3, 7) (4, 6)
# write here
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
[17]:
k = 8
# write here
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
[18]:
x,y = 5,7
#x,y = 8,4
# write here
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
[19]:
y = 4
# write here
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 thanx
, 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
[20]:
x,k = 3,5 # 3 4 5
#x,k = 6,2 # 6 5 4 3 2
#x,k = 4,4 # 4
# write here
Searching a sequence
We are at the airport, and we’ve been told to reach the gate of our trusted airline company Turbulenz. We don’t remember exactly the gate, but we know we have to stop at the first Turbulenz sign we find. If by mistake we went further, we might encounter other gates for international flights, and who knows where we would end up.
If we have to perform searches in potentially long sequences, and we don’t always need a complete visit, using a while
loop is more convenient and efficient than a for
.
We could represent the example above as a list:
[21]:
# 0 1 2 3 4 5 6 7
airport = ['Flyall','PiercedWings','PigeonJet','Turbolenz', 'BoingBoing','Jettons','Turbulenz','BoingBoing']
Once the element is found, we would like the program to print the position in which it was found, in this case 3
.
Naturally, if you read well the list search methods you already know there is a handy method .index('Turbulenz')
, but in this notebook we adopt the philosophy of ‘do it yourself’, and will try building our search algorithms from scratch.
QUESTION: Can you think of some corner case where index
method can also bring a problem?
What we need
To build our search, we will need:
control variable
stop condition
control variable update
The control variable in this case could be an index i
, the stop condition could evaluate whether we reached the end of the airport, and inside the cycle we will update the index to keep searching. But where should we evaluate whether or not we have found the gate? Furthermore, since we are expert programmers we believe in misfortune, and know horror scenarios could happen indeed, like Turbulenz company going bankrupt the very same day of our arrival! Thus, we also need to foresee the case
our search may give no result, and decide what should happen in such situation.
How to check
There are two ways to check a discovery:
most direct way is to place an exit check inside the body of
while
itself: we could put anif
statement which controls when the element is found, and in such case performs the execution of abreak
command. It’s by no means elegant, yet it could be a first approach.a better option would be performing the check in the boolean condition of the
while
, but devising a program which works in all cases could be slightly trickier.
Let’s try them both in the following exercises.
Exercise - Turbolenz with a break
✪✪ Write some code which uses a while
to search the list airport
for the FIRST occurrence of company
: as soon as it is found, stops searching and PRINTS the index where it was found.
If the company is not found, PRINTS ‘Not found’
USE a
break
to stop the searchREMEMBER to test your code with all the suggested airports
Example 1 - given:
company='Turbolenz'
airport = ['Flyall','PiercedWings','PigeonJet','Turbolenz', 'BoingBoing','Jettons','Turbulenz','BoingBoing']
after your code, it must print:
Found the first Turbolenz at index 3
Example 2 - given:
company = 'FlapFlap'
airport = ['PiercedWings','BoingBoing','Turbolenz','PigeonJet']
it must print:
FlapFlap was not found
[22]:
company = 'Turbolenz'
airport = ['Flyall','PiercedWings','PigeonJet','Turbolenz', 'BoingBoing','Jettons','Turbulenz','BoingBoing']
#company = 'FlapFlap'
#airport = ['PiercedWings','BoingBoing','Turbolenz','PigeonJet']
#airport = []
#airport = ['FlapFlap']
#airport = ['Turbolenz', 'FlapFlap']
# write here
Exercise - Turbulenz without break
✪✪ Try now to rewrite the previous program without using break
nor continue
: to verify the finding, you will need to enrich the termination condition.
[23]:
company = 'Turbolenz'
airport = ['Flyall','PiercedWings','PigeonJet','Turbolenz', 'BoingBoing','Jettons','Turbulenz','BoingBoing']
#company = 'FlapFlap'
airport = ['PiercedWings','BoingBoing','Turbolenz','PigeonJet']
#airport = []
#airport = ['FlapFlap']
#airport = ['Turbolenz', 'FlapFlap']
# write here
QUESTION: you probably used two conditions in the while
. By exchanging the order of the conditions in the proposed solution, would the program work fine? If not, in which cases could it fail?
HINT: If you have doubts try reading the chapter booleans - evaluation order
Exercise - hangar
✪✪ Our plane just landed but now it must reach the hangar, dodging all the extraneous objects on the track!
Write some code which given a string track
with a certain number of non-alphanumeric characters at the beginning, PRINTS the word which follows these characters.
Example - given:
track = '★★🏳🏳♦🏳♦🏳🏳hangar★★★'
your code must print:
hangar★★★
YOU CAN’T know beforehand which extra characters you will find in the string
DO NOT write characters like ★🏳♦-_ in the code
HINT: to determine if you have found alphanumerical characters or numbers, use .isalpha()
and .isdigit()
methods
[24]:
track = '★★🏳🏳♦🏳♦🏳🏳hangar★★★' # hangar★★★
#track = '🏳🏳twinengine' # twinengine
#track = '-★♦--♦--747-🏳' # 747-🏳
#track = 'glider' # glider
#track = '__♦__🏳__♦_' # prints nothing
# write here
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.
there is a
road
fromSanta Fe
untilTombstone
to arrive to the treasure, which we represent as a list of stringswe use two indexes
butch
andcarson
to represent where the outlaws are on the roadeach 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 positioncarson
andbutch
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 !
[25]:
# 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
Exercise - The Balance of Language
✪✪ In the sacred writings of Zamfir the Prophet, it is predicted that when all Earth inhabitants speak a language with all the words of same length, universal harmony will be reached among human people. This event is probably far in time and by that epoch the vocabulary of humans will be so wide and varied that checking all the words will certainly require powerful calculations: you are asked to program the underwater servers of Atlantis to perform a check in the centuries to come.
Given a string of words language
, write some code which prints True
if all the words have the same length, False
otherwise.
To have an efficient algorithm, you must use a while
:
stop the loop as soon you can determine with certainty the program result
DO NOT use
break
norcontinue
[26]:
language = "eternal harmony forever" # True
#language = "war and violence" # False
#language = "vi rt uo si ty" # True
#language = "deceit bullying" # False
#language = "harmony crashed today" # False
#language = "peace" # True
#language = "" # True
# write here
Exercise - the tree shaker
✪✪✪ Giustino the farmer decides to radically improve his farm productivity with high-tech devices, and asks you to develop a ‘tree shaker’ (so he calls it..) to perturbate the trees and harvest the exotic fruits he planted in his highlands (thanks to climate change…)
The plantation
is a sequence of fruit trees, elements of the landscape (stones, gravel, etc) and signs S
. The beginning and end of a subsequence of trees is always marked by a sign.
The vehicle to design has a cargo_bed
of capacity 7 where it can store the harvest.
Write some code to scan the plantation
and harvests in cargo_bed
the fruits as they are found.
USE a
while
, stopping as soon as thecargo_bed
is fullDO NOT use
break
norcontinue
DO NOT write fruit names or landscape elements (no
bananas
norrocks
..). You can still write'S'
, though.
Example - given:
[27]:
plantation=['rocks','stones', 'S', 'bananas','oranges','mangos','S', 'sand', 'stones','stones',
'S', 'avocados','S', 'weeds', 'S', 'kiwi', 'mangos', 'S', 'S', 'S',
'rocks','S', 'lime','S', 'pebbles','S', 'oranges','coconuts','S', 'gravel']
after your code, it must result:
>>> print(cargo_bed)
['bananas', 'oranges', 'mangos', 'avocados', 'kiwi', 'mangos', 'lime']
[28]:
# 0 1 2 3 4 5 6 7 8 9
plantation=['rocks','stones', 'S', 'bananas','oranges','mangos','S', 'sand', 'stones','stones',
# 10 11 12 13 14 15 16 17 18 19
'S', 'avocados','S', 'weeds', 'S', 'kiwi', 'mangos', 'S', 'S', 'S',
# 20 21 22 23 24 25 26 27 28 29
'rocks','S', 'lime','S', 'pebbles','S', 'oranges','coconuts','S', 'gravel']
#plantation = ['S','S'] # []
#plantation = ['S','lemons','S'] # ['lemons']
#plantation = ['sand','S','lemons','S'] # ['lemons']
#plantation = ['oranges'] # []
#plantation = ['S','1','2','3','4','5','6','7', '8','S'] # ['1','2','3','4','5','6','7']
#plantation = ['S','1','2','S','x','S','3','4','5','6','7','8','S','9'] # ['1','2','3','4','5','6','7']
cargo_bed = []
# write here
['bananas', 'oranges', 'mangos', 'avocados', 'kiwi', 'mangos', 'lime']
Exercise - the ghost castle
✪✪✪ Given a string
and two characters char1
and char2
, write some code which PRINTS True
if all occurrences of char1
in string
are always followed by char2
Example - given:
string,char1,char2 = 'fantastic story of the ghost castle', 's','t'
prints True
because all the occurrences of s
are followed by t
string,char1,char2 = "enthusiastic dadaist", 's','t'
prints False
, because the sequence si
is found, where s
is not followed by t
USE a
while
, try to make it efficient by stopping as soon as possible.DO NOT use break
DO NOT use any search method (no
index
,find
,replace
,count
…)
[29]:
string,char1,char2 = 'fantastic story of the ghost castle', 's','t' # True
#string,char1,char2 = "enthusiastic dadaist", 's','t' # False
#string,char1,char2 = "beetroots", 'r','o' # True
#string,char1,char2 = "beetroots", 'e','o' # False
#string,char1,char2 = "a", 'a','b' # False
#string,char1,char2 = "ab", 'a','b' # True
#string,char1,char2 = "aa", 'a','b' # False
# write here
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
:
[30]:
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!
[30]:
Looking at the code, we can notice that:
the variable
deck
is initializedwe verify that
deck
dimension is greater than zeroat each step the list
deck
is MODIFIED by reducing its dimensionit 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:
we find hearts, and interrupt the search
there aren’t heart cards, and the deck is exhausted
In any case, in the end we must tell a result to the user. To do so, it’s convenient to initialize card
at the beginning like an empty string, so we can handle 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 uncommenting the second deck which has no hearts cards, and check the different executions.
[31]:
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!
[31]:
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
[32]:
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
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):
while []: print('z') print('BIG')
while ['a']: print('z') print('BUG')
la = [] while len(la) < 3: la.append('x') print(la)
la = ['x','y','z'] while len(la) > 0: print(la.pop())
la = ['x','y','z'] while la: print(la.pop(0))
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
[33]:
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]
[34]:
lst = []
i = 0
# write here
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
[35]:
stack = ['H-Middle Ages', # <---- bottom
'T-Australia',
'T-Scotland',
'D-Suspects',
'T-Caribbean'] # <---- top
travel = []
# write here
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'
characterAfter 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: []
[36]:
left_stack = ['box','boot','horseshoe','bucket']
right_stack = ['bin','saddle','tin can']
shoot = 'R'
#shoot = 'L'
#left_stack = ['bucket', 'box']
# write here
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. attaches14
)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 []
[37]:
la = [3,5,6,7]
# write here
Continue
Go on with the challenges
[ ]: