Recall the **while** loop from previous lecture.

In [1]:

```
n = 1000
a = 1
while a ** 3 < n:
print a ** 3, # mind the comma
a = a + 1
print "end"
```

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

In [2]:

```
a = input()
while a != 5:
print a
a = input()
```

Let's do the same as above but also sum the numbers.

In [3]:

```
n = 0
a = input() # input first
while a != 0:
n = n + a
a = input() # input second
print n
```

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 evaluates the condition at the end of the loop.

`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"""
```

An other type of loop would be unnecessary.

The previous example **without code repetition**:

In [4]:

```
n = 0
while True: # start the loop
a = input() # input once, no repetition
if a == 0: # halt condition
break # halt
n += a # the actual body of the loop
print n
```

General purpose, commmon programming techniques.

a.k.a. **accumulation**

Despite the name, it is not only for 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.

In [5]:

```
n = 0 # accumulator variable
a = input() # read the first
while a != 0: # halt condition
n = n + a # summation
a = input() # read the rest
print n
```

It is not only for addition:

In [6]:

```
n = 1 # accumulator variable
a = input() # read the first
while a != 0: # halt condition
n = n * a # summation
a = input() # read the rest
print n
```

For a series of objects we wish to count the number of elemnets with a given property (for example count the odd numbers).

In [8]:

```
c = 0 # counter variable
a = input() # read the first
while a != 0: # halt condition
if a % 2 == 1: # check the desired property
c += 1 # increase counter
a = input() # read the rest
print c
```

`string`

s until an empty string arrives and count the words containing the letter `e`

!

In [6]:

```
c = 0
word = raw_input()
while word != "":
if "e" in word:
c += 1
word = raw_input()
print c
```

`input`

is a security risk. There is a bit more secure way to read inputs if you know what type you want: wrap the `raw_input`

function into the desired type:

In [7]:

```
numer = int(raw_input())
print number
```

For a given set of objects one wishes to find the best/worst element. Best/worst is ment by some aspect, it can be smallest/largest.

For example find the largest of some positive numbers.

In [8]:

```
largest = 0 # default extremum
a = input() # read first
while a > 0: # halt condition
if largest < a: # compare to previous extremum
largest = a # update extremum
a = input() # read next
print "the largest:", largest
```

Same without code-repetition:

In [9]:

```
largest = 0
while True:
a = input()
if a <= 0:
break
if largest < a:
largest = a
print "the largest:", largest
```

Find out if any of a given set of objects satisfy some condition. For example in prime testing if any of the smaller numbers is a divisor then it is not a prime.

In [11]:

```
n = input() # read the number
a = 2 # variable for iterating over the possible divisors
hit = False # this variable remembers whether the condition is met
while a < n and not hit: # halt condition (halt if already found one)
if n % a == 0: # condition
hit = True # it's a hit
a += 1 # go for the next
print not hit # prime if the hit is False (no divisor)
```

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

How many primes are there under 1000? Put a *find any* (prime test) inside a counting paradigm!

In [9]:

```
number = 2 # first number to check
prime_count = 0 # counter variable in the counting paradigm
while number < 1000: # counting paradigm starts here
divisor = 2 # first element of the "find any" part
composite = False # hit variable
while divisor < number and not composite: # loop for "find any"
if number % divisor == 0: # check for hit
composite = True # set hit variable
divisor += 1 # next element to check in "find any"
if not composite: # end of "find any"
prime_count += 1 # if found then increase counter variable
number += 1 # next in counting loop
print prime_count
```

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

In [14]:

```
l = [1, 2, 5]
```

Don't call a list object `list`

because it is already the name of the type!

In [15]:

```
l = [1, 5.3, "dog", [1, 2, 5], 12, "cat"]
```

A given element can be accessed by index:

In [16]:

```
l = ["a", "b", "c"]
print l[0]
print l[1]
print l[2]
```

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

Access a sublist. Mind that intervals are **inclusive from left and exclusive from right**.

In [10]:

```
l = ["a", "b", "c", "d", "e", "f"]
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)
```

In [11]:

```
l[-2] # negative index is calculated from the back
```

Out[11]:

You can concatenate lists just like strings:

In [12]:

```
print [1, 2, 5] + [8, 5, 3]
```

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

In [13]:

```
s = "puppy"
print s[2]
print s[1:4]
print s[-1::-1]
```

In [14]:

```
l = [1, 2, 5]
l[2] = 3
print l
```

The same cannot be done with strings:

In [15]:

```
s = "puppy"
s[1] = "a"
print s
```

You can manipulate strings but not this way!

In [16]:

```
print range(4)
```

In [17]:

```
print range(4, 10)
```

In [18]:

```
print range(3, 15, 3)
```

As you can see, it works like list indexing ("from", "to" and optional "step").

- If you give one parameter, 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 [29]:

```
l = range(1, 4)
l[2] = 5
print l
```

The `append`

method inserts a new elements at the end:

In [30]:

```
l = [1, 2, 5]
l.append(4)
print l
```

In [31]:

```
l = []
a = input()
while a != 0:
l.append(a)
a = input()
print l
```

The `insert`

method inserts a new element to a given place:

In [34]:

```
l = [1, 2, 5]
l.insert(1, 1.5)
print l
```

`pop`

erases an element with a given index:

In [19]:

```
l = [1, 2, 4, 2, 5]
l.pop(2)
print l
```

`remove`

erases a given element (its first occurrance):

In [36]:

```
l = [1, 2, 3, 2, 2, 5]
l.remove(2)
print l
```

In [37]:

```
l = [1, 2, 2, 2, 5]
while 2 in l:
l.remove(2)
print l
```

The `len`

function gives the length:

In [38]:

```
l = [1, 2, 5]
print len(l)
```

The `count`

method gives how many times a given element occurrs:

In [39]:

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

The `sort`

method sorts:

In [40]:

```
l = [1, 2, 3, 4, 1, 2, 1, 4, 5, 1, 3, 2, 4]
l.sort()
print l
```

In Python the `for`

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

In [22]:

```
l = [1, 2, 5, "puppy"]
for elem in l:
print elem
```

One can iterate index-wise not element-wise. Use the `range`

in that case:

In [23]:

```
l = [1, 2, 5, "puppy"]
for i in range(len(l)):
print l[i]
```

How does it work? The command `range(len(l))`

gives you exactly the indices of the list.

In [24]:

```
l = [1, 2, 5, "kutya"]
for i in range(len(l)):
print "index: ", i, " element: ", l[i]
```

In [25]:

```
l = [1, 2, 5]
n = 0
for e in l:
n += e
print n
```

In [26]:

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

In [27]:

```
l = [1, 2, 5, 6, 15, 4, 6, 7, 8]
largest = l[0]
for e in l:
if largest < e:
largest = e
print largest
```

In [29]:

```
n = input()
composite = False
for divisor in range(2, n):
if n % divisor == 0:
print divisor
composite = True
break
print not divisor
```

Let's count how many `"e"`

letters are in those strings which contain the letter `"a"`

!

In [31]:

```
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
```

With the use of the `count`

method, you only have to use a counting paradigm:

In [32]:

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

In [ ]:

```
```