Python: Loops & Lists

For-Loop

A basic principle of programming is a sequence of iterations: doing things multiple times. This is called a loop.
There are basically two methods of loops:

  • for-loop

  • while-loop

For now we focus on the for-loop.

We can use it if we wan’t to execute a block of code n times. For that we’ll use the build-in method range():

for i in range(3):
    # do something n times 
    print('one iteration')
    print('~ '* 7)
one iteration
~ ~ ~ ~ ~ ~ ~ 
one iteration
~ ~ ~ ~ ~ ~ ~ 
one iteration
~ ~ ~ ~ ~ ~ ~ 
for i in range(4):
    print(i)
0
1
2
3

Syntax

A for loop is indicated by the keyword for, followed by a variable (name of your choice) and another keyword in, followed by an iterable object. Behind that we have to insert a :.

Everything inside a loop is indent by one tab. This block of code is repeated for every iteration over the iterable object.
The first line of code without that extra indent is the first line that is not part of the loop.

for i in range(5):

    print('🦜' * (i+1))
    
print('🌵')
print(2*'☕')
🦜
🦜🦜
🦜🦜🦜
🦜🦜🦜🦜
🦜🦜🦜🦜🦜
🌵
☕☕

As you see we can use the variable i inside the loop. Its value changes with every iteration. Notice that counting starts from 0 in programming languages!

# We can specify a start value inside the range function:
for page_number in range(2,11):
    print(page_number)
2
3
4
5
6
7
8
9
10
# Furthermore we can specify the steps between two values:
for size in range(12, 24, 2):
    print(size)
12
14
16
18
20
22
Task: Create a copy of the code that we've used to create the first book. Insert a for-loop and use the method add_page() inside the loop to add multiple pages.

Tip: If you want to use the numbers inside a text field, make sure to cast them into strings.

Lists

We have seen spatial dimensions of variables.
The data itself also has a spatial dimension. So far we have used mainly single values like a number stored in a variable, but most data is stored in sequences:
  • a word is a sequence of characters
  • a image is a sequence of numbers
  • a video is a sequence of sequences of numbers

We can store a sequence of data in a data type called list. The syntax for a list are square brackets: [ ]. The items of the sequence are placed inside the square brackets, separated by ,.

numbers = [1, 5, 734, 25, 84, 101]
print(numbers)
print(type(numbers))
[1, 5, 734, 25, 84, 101]
<class 'list'>

We can get the length (= number of items) of a list with the built-in function len(). (We can use it to get the length of serveral other objects as well.)

len(numbers)
6
You can imagine a list for e.g. as an advent calendar. Each space in the sequence contains data and we can access each one independently.

calendar.jpg Source

# syntax: name_of_variable = [item1, item2, item3]
advent_calendar = ['apple', 'beer', 'cherry', 'date']
len(advent_calendar)
4
print(advent_calendar)
['apple', 'beer', 'cherry', 'date']

Accessing elements of a list

All items in a list have an index, through which we can access items individually. Access elements of a list with the following syntax:

name_of_list[index] # index is an integer
item_2 = advent_calendar[2]
print(item_2)
cherry

We expected to get a beer, but got a cherry.

Task: Get the beer.

Remember that counting starts from 0, not from 1.
This also means that the last item has the length of the list - 1.

print(len(advent_calendar))

last_item = advent_calendar[len(advent_calendar) - 1]
print(last_item)
4
date

As you see we can use methods and mathematical expressions inside the square brackets.
But we have to make sure that the result is an integer.

some_item = advent_calendar[len(advent_calendar) / 2]
print(some_item)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_24181/3150626410.py in <module>
----> 1 some_item = advent_calendar[len(advent_calendar) / 2]
      2 print(some_item)

TypeError: list indices must be integers or slices, not float
Task: Modify the code from above so that the mathematical expression works.
some_item = advent_calendar[int(len(advent_calendar) / 2)]
print(some_item)
cherry

We can access values from the end of a list. For that we have to use a negative index.

print(advent_calendar)
print(advent_calendar[-1]) # Counting from the end starts at -1, not -0!
['apple', 'beer', 'cherry', 'date']
date
print(advent_calendar)
print(advent_calendar[-2])
['apple', 'beer', 'cherry', 'date']
cherry

We can access a range (slice) of elements:

print(advent_calendar)
print(advent_calendar[1:3]) # Start at index 1, stop at 3 (3 not included).
['apple', 'beer', 'cherry', 'date']
['beer', 'cherry']
print(advent_calendar)
print(advent_calendar[:3]) # No start value = start at 0, stop at 3 (not included).
['apple', 'beer', 'cherry', 'date']
['apple', 'beer', 'cherry']
print(advent_calendar)
print(advent_calendar[2:]) # No stop value = stop at end (inclusive).
['apple', 'beer', 'cherry', 'date']
['cherry', 'date']

list_slicing.jpg

Built-in methods of data type list

Adding values

append() adds one element at the end of the list.

advent_calendar.append('elephant') # list.append(element)
print(advent_calendar)
['apple', 'beer', 'cherry', 'date', 'elephant']

Removing values

With remove() we can remove a specific element from the list. (This removes only the first occurence of that element.)

print(advent_calendar)
advent_calendar.remove('beer') # list.remove(element)
print(advent_calendar)
['apple', 'beer', 'cherry', 'date', 'elephant']
['apple', 'cherry', 'date', 'elephant']

The method pop() returns and removes the last item.

# Get and delete the last item.
print(advent_calendar)
print(advent_calendar.pop())
print(advent_calendar)
['apple', 'cherry', 'date', 'elephant']
elephant
['apple', 'cherry', 'date']

If we use an integer as argument for pop(), the item of this index is returned and removed.

# Get and delete an item by index
print(advent_calendar)
advent_calendar.pop(1)
print(advent_calendar)
['apple', 'cherry', 'date']
['apple', 'date']

Inserting values

Instead of appending an element at the end we can specify a index with insert().

print(advent_calendar)
advent_calendar.insert(1, 'banana') # list.insert(index, value)
print(advent_calendar)
['apple', 'date']
['apple', 'banana', 'date']

Replacing values

print(advent_calendar)
advent_calendar[1] = 'berry' # list[index] = value
print(advent_calendar)
['apple', 'banana', 'date']
['apple', 'berry', 'date']

Combining lists

additional_elements = ['mango', 'firebird', 'eel']
advent_calendar += additional_elements # list + list
print(advent_calendar)
['apple', 'berry', 'date', 'mango', 'firebird', 'eel']

Sorting lists

Sorting is done “in place”. This means that the list itself is modified (elements inside the list are sorted) and no new list is returned.

advent_calendar.sort() # No argument = ascending order.
print(advent_calendar)
['apple', 'berry', 'date', 'eel', 'firebird', 'mango']
advent_calendar.sort(reverse=True)
print(advent_calendar)
['mango', 'firebird', 'eel', 'date', 'berry', 'apple']
advent_calendar.sort(key=len)
print(advent_calendar)
['eel', 'date', 'mango', 'berry', 'apple', 'firebird']
advent_calendar.sort(key=len, reverse=True)
print(advent_calendar)
['firebird', 'mango', 'berry', 'apple', 'date', 'eel']

With .reverse() we reverse a list, but this method does not sort it.

advent_calendar.reverse()
print(advent_calendar)
['eel', 'date', 'apple', 'berry', 'mango', 'firebird']

Iterating over a list with a for-loop

So far we have used a for-loop in combination with the iterable object range.

for i in range(3):
    print(i)
0
1
2

In fact range produces a list of items and iterates over these items.

So we can use a for-loop to iterate over a list of items directly. For each item in the sequence, the code inside the loop is executed once.

advent_calendar = ['apple', 'beer', 'cherry', 'date']

for surprise in advent_calendar:
    print(surprise)
apple
beer
cherry
date

loop_list.jpg

If you need the index of each item, it’s easier with the built-in function enumerate(), which returns the index and the value of the item.

animals = ['🐢', '🦓', '🐫', '🐼', '🐤']
animals_green = ['🦜', '🐊', '🐢', '🦎', '🐉', '🐍', '🐲','🦟', '🦖','🦚']

for index, animal in enumerate(animals+animals_green):
    print(index, ':', animal)
0 : 🐢
1 : 🦓
2 : 🐫
3 : 🐼
4 : 🐤
5 : 🦜
6 : 🐊
7 : 🐢
8 : 🦎
9 : 🐉
10 : 🐍
11 : 🐲
12 : 🦟
13 : 🦖
14 : 🦚

index and value are variables, so we can name them as we like. For this example, we could for example use

for i, surprise in enumerate(advent_calendar):
    print(i, ':', surprise)

On the other hand we can use range() to generate elements for a list:

for n in range(5, 10):
    print(n)
5
6
7
8
9
numbers = [n for n in range(5, 10)]
print(numbers)
[5, 6, 7, 8, 9]

We create a new variable and use square brackets on the right side of the equal sign. Then we execute a for-loop with range() inside the square brackets. The variable before the for keyword indicates that the element will be included into the list.

numbers = [n/2 for n in range(5, 10)]
print(numbers)
[2.5, 3.0, 3.5, 4.0, 4.5]

Data types inside a list

A list can contain any other python object.
For example we could store coordinates in three separate objects, but we can store them as one object of data type list:

list_init.jpg

x, y, z = 10, 12, 9 # Three objects.
coordinates = [10, 12, 9] # One object of type list.
print(coordinates)
[10, 12, 9]

As lists can contain any other objects they can contain other lists as well.

list_lists.jpg

Furthermore a list can contain items of different data types!

num_list = [num for num in range(0, -7, -2)]

mixed_type_list = [0, 'some words', 3.13, -4.24e-13, num_list]

for item in mixed_type_list:
    print(item, '🐍', type(item))
0 🐍 <class 'int'>
some words 🐍 <class 'str'>
3.13 🐍 <class 'float'>
-4.24e-13 🐍 <class 'float'>
[0, -2, -4, -6] 🐍 <class 'list'>