# While loop¶

The while loop checks the condition before the block is executed, this control structure is also called pre-test loop.

In [1]:
n = 1000
a = 1
while a ** 3 < n:
print(a ** 3, end=' ')  # to print them in one line
a = a + 1
print("end")

1 8 27 64 125 216 343 512 729 end


Let's write a loop that reads numbers until a certain condition is met!

Example: Write a code that reads numbers until get 0, then stops and prints the sum of the numbers.

In [2]:
n = 0
a = float(input())         # input first
while a != 0:
n = n + a
a = float(input())     # input second
print(n)

1
2
0
3.0


In this program we repeated a part of the code!

Example: Rewrite the previous program without code repetition!

In [3]:
n = 0
while True:                 # beginning of the loop
a = float(input())      # input and convert once, no repetition
if a == 0:              # halt condition
break               # exit out from the loop
n += a                  # if the loop is continued (same as n = n + a)
print(n)

1
2
0
3.0


As you can see certain parts of the code is repeated: read the first number than read inside the while loop.

In other languages there is a do...while which checks the condition at the end of the loop. That one is called post-test loop. Two typical forms are

do ... while ...

or

do... until ...

This is missing from python by design. It can be replaced with the following:

while True:
<preparation>
if <halt condition>:
break
<further commands>


# Basic programming elements¶

General purpose, commmon programming techniques.

## Accumulation (summation)¶

If you have a series of numbers (or any other objects) and you want to collect (or accumulate) some information about them then you can use this paradigm.

Example: Calculate the sum of some numbers different from 0. Read the numbers from the standard input, where 0 means the end of sequence.

In [4]:
sum = 0                 # accumulator variable
while True:             # loop
a = float(input())  # input and convert
if a == 0:          # halt condition
break
sum += a            # summation
print(sum)

1
2
0
3.0


Question: What do we have to get if the sequence of numbers is empty?

Example: Multiply the numbers reading from the standard input. What de we have to get when the sequence of numbers is empty? Now, mark the end of the sequence with an empty string, that is, an empty ENTER in the input field. Beware, an empty string cannot be converted to a number!

In [5]:
prod = 1                # accumulator
while True:             # loop
a = input()         # input
if a == "":         # halt condition
break
prod *= float(a)    # convert and product
print(prod)

23
110

2530.0


## Counting¶

For a series of objects we wish to count the number of elemnets with a given property.

Exercise: In a sequence of integer numbers not containing 0, count the odd numbers. The end of sequence is given by 0.

In [6]:
counter = 0             # counter
while True:             # loop
a = int(input())    # input and convert
if a == 0:          # halt condition
break
if a % 2 == 1:      # check the desired property
counter += 1    # increase counter
print(counter)

1
11
111
2
4
0
3


Example: Read strings until an empty string arrives and count the words containing the letter ő !

In [7]:
counter = 0
while True:
string = input()
if string == "":
break
if "ő" in string:
counter += 1
print(counter)

erdő, mező
Erdős Pál
tree, forest, field

2


## Finding extremum¶

For a given set of objects which are comparable, one wishes to find the best/worst element. E.g. it can be smallest/largest.

Example: Find the largest of some non negative numbers.

In [8]:
largest = 0              # default extremum
while True:              # halt condition
a = float(input())   # read and convert
if a <= 0:           # halt condition
break
if largest < a:      # compare to previous extremum
largest = a      # update extremum
print("the largest =", largest)

12
432
1
-2
the largest = 432.0


Example: Change the code for any type of numbers (pozitive or negative). The empty input means the end of sequence.

In [9]:
largest = float('-inf')   # -∞ is the largest for an empty set
while True:               # loop
a = input()           # input
if a == "":           # halt condition
break
f = float(a)          # convert here!
if largest < f:       # compare
largest = f       # refresh the extremum
print("The largest =", largest)

-234
-3
-55

The largest = -3.0


## Find any¶

Find out if any of a given set of objects satisfy some condition.

Example: Write a prime testing program for integers greater than 1 with searching a divisor up to the square root of the given number.

In [10]:
n = int(input())                 # read a number
d = 2                            # d is iterating over the possible divisors
hit = False                      # remembers whether the condition is met
while d**2 <= n and not hit:     # halt if a divisor is found
if n % d == 0:               # is d a divisor?
hit = True               # it's a hit
d += 1                       # go for the next
if not hit:                      # n is prime if no divisor found
print("The number {0} is a prime.".format(n))
else:
print("{0} is a composite number.".format(n))

499
The number 499 is a prime.


## Combining these programming elements¶

For more complicated tasks, you may combine the technics given above. It is not the only way to solve programming exercises but it's a good start. Feel free to experiment with different solutions.

Example: How many primes are there under 1000? Put a find any (prime test) inside a counting code!

In [11]:
num = 2                           # first number to check
primes = 0                        # counter
while num <= 1000:                # counting starts here
divisor = 2                       # the embedded "find any" starts here
composite = False                 # hit bool variable
while divisor**2 <= num:          # loop for "find any"
if num % divisor == 0:        # check for hit
composite = True          # set hit variable
break
divisor += 1                  # next element to check in "find any"
if not composite:             # if found
primes += 1               #         then increase the counter
num += 1                      # the next number to check
print(primes)

168


# Lists¶

Lists are containers for a sequences of objects. For example store numbers:

In [12]:
l = [1, 2, 5]
type(l)

Out[12]:
list

Don't call a list object list because it is already the name of the type!

The list can be given with a square bracket, the emelents are comma separated list between the brackets. The elements of the list can be various objects, not necessarily of the same type (even lists).

In [13]:
l = [1, 5.3, "dog", [1, 2, 5], 12, "cat"]

In [14]:
l

Out[14]:
[1, 5.3, 'dog', [1, 2, 5], 12, 'cat']

## List indexing, sublists¶

A given element can be accessed by index:

In [15]:
l = ["a", "b", "c"]
print(l[0], l[1], l[2])

a b c


As you can see the list indices start with $0$ and goes up to $n-1$ where $n$ is the length of the list.

The connection between indexing from 1 to n and indexing in Python from 0 is explained by this figure:

 ____ ____ ____ ____ ____
|    |    |    |    |    |
| e1 | e2 | e3 |....| en |
|____|____|____|____|____|
Λ    Λ    Λ    Λ    Λ    Λ
0    1    2    ... n-1   n
-n  1-n  2-n        -1

How to access a sublist. Mind that intervals are inclusive from left and exclusive from right.

In [16]:
l = [0, 1, 2, 3, 4, 5]
print(l[1:3])       # from 1 to 3 (1 is actually the second)
print(l[2:])        # from index 2 to the end
print(l[:3])        # from the beginning up to index 3 (index 3 is not included)
print(l[0:4:2])     # from the start to index 4, take every second element
print(l[-1::-1])    # from last to first with -1 steps (reverse)

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

In [17]:
l[-2] # negative index is calculated from the back

Out[17]:
4

You can concatenate lists just like strings:

In [18]:
print([1, 2, 5] + [8, 5, 3])

[1, 2, 5, 8, 5, 3]


All the above works for strings (as they are list of characters):

In [19]:
s = "trio"
print(s[1:4])
print(s[-2::-1] + s[-1])
print(s[::2])
print(s[1::2])

rio
irto
ti
ro


There are differences between strings and lists. One can assign a given value in a list (mutable) but not in a string (immutable).

In [20]:
l = [1, 2, 555]
l[2] = 3
print(l)

[1, 2, 3]


The same cannot be done with strings:

In [21]:
s = "puppy"
s[1] = "a"
print(s)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-2e77e6442470> in <module>
1 s = "puppy"
----> 2 s[1] = "a"
3 print(s)

TypeError: 'str' object does not support item assignment

You can manipulate strings but not this way!

## Methods for list manipulations¶

We learn some practical functions/methods for lists.

### Range¶

The range object can be used to create a list. It is a “lazy iterable” in the sense that it doesn’t generate every number that it “contains” when we create it. Instead it gives those numbers to us as we need them when looping over it. (It is not an iterator, what we will learn later.)

In [22]:
list(range(4))

Out[22]:
[0, 1, 2, 3]
In [23]:
range(4) == [0, 1, 2, 3]

Out[23]:
False
In [24]:
list(range(4, 10))

Out[24]:
[4, 5, 6, 7, 8, 9]
In [25]:
list(range(3, 15, 3))

Out[25]:
[3, 6, 9, 12]

As you can see, it works like list indexing:

range(start, end, step)

• If you give one parameter (end), then its the last index (zero included, the last excluded)
• If you give two parameters, then its a [from...to) list
• The optional third parameter is the step size (1 by default)

They can be manipulated as lists.

In [26]:
range(0, 5, 2)[2]

Out[26]:
4
In [27]:
range(1, 10, 2)[1::2]

Out[27]:
range(3, 11, 4)
In [28]:
list(range(1, 10, 2)[1::2])  # [1, 3, 5, 7, 9] -> [3, 7]

Out[28]:
[3, 7]

### New elements / erasing elements¶

The append method inserts a new elements at the end:

In [29]:
l = [1, 2, 5]
l.append(4)
print(l)

[1, 2, 5, 4]

In [31]:
l = []
while True:
a = input()
if a == "":
break
l.append(a)
print(l)

apple
tree
2

['apple', 'tree', '2']


The insert method inserts a new element to a given place:

In [32]:
l = [1, 2, 5]
l.insert(1, 'X')
print(l)

[1, 'X', 2, 5]


The pop method erases an element with a given index. This function return the deleted element. Calling with empty argument list delete the last element.

In [33]:
print(l.pop(1))
print(l)

X
[1, 2, 5]

In [34]:
print(l.pop())
print(l)

5
[1, 2]


The remove method erases the first occurrance of the given element:

In [35]:
l = [1, 2, 3, 2, 2, 5]
l.remove(2)
print(l)

[1, 3, 2, 2, 5]

In [36]:
while 2 in l:
l.remove(2)
print(l)

[1, 3, 5]


The del command is deleting elements with given indices:

In [37]:
l = list(range(8))
del l[::2]
print(l)
del l[1::2]
print(l)
del l[:]            # delete everythin, like l.clear()
print(l)

[1, 3, 5, 7]
[1, 5]
[]


### Further list operations¶

The len function gives the length:

In [38]:
l = [1, 2, 5]
print(len(l))

3


The count method gives how many times occurrs a given element:

In [39]:
l = [1, 2, 3, 4, 1, 2, 1, 4, 5, 1, 3, 2, 4]
print(l.count(1), l.count(4), l.count(15))

4 3 0


The sort method sorts changing the list. The sorted function construct a new (sorted) list.

In [40]:
l = [1, 2, 3, 4, 1, 2, 1, 4, 5, 1, 3, 2, 4]
l.sort()
print(l)

[1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5]

In [41]:
l = [1, 2, 3, 4, 1, 2, 1, 4, 5, 1, 3, 2, 4]
sorted(l)

Out[41]:
[1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5]
In [42]:
l

Out[42]:
[1, 2, 3, 4, 1, 2, 1, 4, 5, 1, 3, 2, 4]

# For loop¶

In Python the for loop and lists are hand-in-hand. A for loop can iterate through lists (and other iterable objects):

for <loop variable> in <iterable object>:
<statements>
else:
<statements>

In [43]:
l = ["puppy", "cat", "mouse", "cicada"]
for e in l:
print(e, end=" -> ")
print("...")

puppy -> cat -> mouse -> cicada -> ...


One can iterate index-wise instead of element-wise. Use the range in that case:

In [44]:
# element-wise
l = [2, 3, 5, 7, 11]
for i in l:
print(i, end=" ")

2 3 5 7 11
In [45]:
# index-wise
l = [2, 3, 5, 7, 11]
for i in range(len(l)):
print(l[i], end=" ")

2 3 5 7 11
In [46]:
# print index and element
l = [2, 3, 5, 7, 11]
for i in range(len(l)):
print("index:", i, "element:", l[i])

index: 0 element: 2
index: 1 element: 3
index: 2 element: 5
index: 3 element: 7
index: 4 element: 11


What happen when we have an else-branch in the for-loop?

In [47]:
for e in range(0,10,2):
if e % 2 == 1:
break
print(e, end=" ")
else:                     # the else-branch is exetuted at the end
print("all are even") # as we never jumped out from the for-loop

0 2 4 6 8 all are even

In [48]:
l = [0, 2, 4, 5, 6, 8]    # there is an odd number in this list
for e in l:
if e % 2 == 1:
break
print(e, end=" ")
else:                     # now the else-barnch is not executed
print("all are even")

0 2 4

## Programming elements for lists¶

### Accumulation/Summation¶

In [49]:
l = [1, 2, 5]
n = 0
for e in l:
n += e
print(n)

8


### Counting¶

In [50]:
l = [1, 2, 5, 6, 4, 6, 7, 8]
c = 0
for e in l:
if e % 3 == 0:
c += 1
print(c)

2


### Finding extremum¶

In [51]:
l = [1, 2, 5, 6, 15, 4, 6, 7, 8]
largest = l[0]    # for the case when the list is surely not empty
for e in l[1:]:
if largest < e:
largest = e
print(largest)

15


### Find any¶

In [52]:
lista = [0, 2, 4, 5, 6, 8]
for elem in lista:
if elem % 2 == 1:
print("there is an odd")
break
else:
print("all are even")

there is an odd


### Combining programming elements¶

Example: Let's count how many "e" letters are in those strings which contain the letter "a" !

In [53]:
words = ["puppy", "elf", "cat", "elephant", "littlecat"]
c = 0
for word in words:
if "a" in word:
for i in range(len(word)):
if word[i] == "e":
c += 1
print(c)

3


With the use of the count method, you only have to use a counting paradigm:

In [54]:
words = ["puppy", "elf", "cat", "elephant", "littlecat"]
c = 0
for word in words:
if "a" in word:
c += word.count("e")
print(c)

3

In [ ]: