# B2.2.2 Lists in Python
:::info
This is a note part of the coding course for IB Computer Science program. If you want to check out other parts of the same course you can see them in [This link of teaching material](/68GDv_RgT-yh9oERMvdnFw)
:::
This notes covers the essentials of a set for IB Diploma. In the previous syllabus this was covered with Arrays. Lists and arrays are not the same but they have some similarities.
This note include B2.2.2
## One variable, multiple values
We have covered already that we have variables, and we're used that when we have one variable, we have one value for example:
```python=
x=5
y=6
potato="tomato"
```
But sometimes we want to have **more than one value in a variable** and for that we're going to use what is called, in an abstract way, _collections_. They allow to have more than one value in just one variable, fancy, right?
In python we have several ways to work with them, let's name a few of them and some characteristics and differences.
| Type| Set |Tuple | List | Diccionary |
|--- |--- |--- | --- | --- |
| Iterable | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Duplicate values? |:x: |:white_check_mark: | :white_check_mark: |:x: |
| Ordered? | :x: | :white_check_mark: |:white_check_mark: |:white_check_mark: ^1^ |
Changeable? | :x:^2^ | :x: | :white_check_mark: |:white_check_mark: |
Use keys?| :x: | :x: | :x: |:white_check_mark: |
Syntax| `{ , }` |`( , )` |`[ , ]` | `{ : , : }` |
Example| `{a,b,c,d}` |`(a,b,c,d)` |`[a,b,c,d]` | `{a:valueA,b:valueB}` |
```!
1: In Python dictionaries are ordered since python 3.7, before they were unordered.
2: What you cannot changes are the _items_ in the set, but you can add or delete elements to the set.
```
## B2.2.1 Static and dynamic data strucures
In IB we need to discuss static and dynamic data structures. This is going to happen in an exam.
Static data structures have a fixed sized set in compile time (before the program is executed). The classic static data structure is the **Array** or **multi-dimensional arrays**. We have used in class **Arrays** with the [Sounds with arduino](/I0rOqB99RMGA62qFLcx1Vg)
Dynamic data structures can vary in size in execution time. Lists, queues, trees, graphs, stacks are examples of this. In Python all we have are dynamic data structures.
### Characteristics
* **Flexibility**. Dynamic data structures are more flexible as you may guess.
* **Memory usage** If it's optimized, static data structures can be more efficient, since dynamic data structures they have some "friction". But in the other hand, if not optimized, the static data structure needs to allocate a lot of "empty" spots, whereas the dynamic data structure only allocate the size it needs.
* **Speed** For accessing elements using indexes static data structures are the fastest in town, also because they tend to allocate data one next to the other without data fragmentation. However we will deep dive on this in Big O Notation.
:::info
**Data fragmentation**
If you remember from [A1.1 Notes and resources](/6LgCmT4IToOkOu0CuV3UBQ) I linked this video from Branch Education:
https://www.youtube.com/watch?v=16zrEPOsIcI
There you can see an analogy of the memory. In this case that would be the secondary memory. But for our porpuses this will be the RAM

If we have a dynamic data type such a list in python, the python interpeter is going to add the elements of a wherever it fits so you will have your list of number scattered through the ram like this.

(the red lines are your elements in your data structure)
If you use an array that is fixed in size, when is allocated, it will try to be all together

As you might guess, for accessing is quite _faster_
:::
Now back to lists
## Why lists
Even if all of these types are interesting, we're going to focus on lists because strings are sequences and there is another common type that is also consider a sequence: Strings (str in Python)
That means that we can apply a lot of what we know to both (yay), even if there are some differences (not yay)
## Creation, genesis of a list
We can create in python a list in different ways:
1) We can just say create an empty list `a= []` with the square brackets. Later we can add the elements in the list
2) We can fill those elements directly separating them between comas `myList = ["carrot", "letucce", "cabbage"]` or `superDuperList = [5, 3, 0, 10, 5]`
3) We can use a special function called **constructor** list() empty or with a parameter and it's going to create a list with that. For example `x = list()` is going to create an empty list and `numbers = list(range(10))` (range is another function that we didn't cover, for now, if you don't know it, it's ok it's just a function that retrieves something that can be converted into a list)
4) We can use list comprenhension that is put into brackets something that can be converted into a list. It's a bit advance for now but has the shape of this ` myCoolList =[x for x in iterable]` but we haven't covered loops yet!
:::info
Lists in python can have several types inside of them, you can have a list with booleans, string, numbers, complex types. This is not common in other programming (specially if they are statically typed).
:::
So let's create a simple list!
### Exercise. Simple lists
:::info
**Naming convention**, even if in the exam we're not going to have this, is useful for writing variables that are lists (or other types of collections) names that are in **plural** like `grades` or `students` or `names` so we can have a hint that they are a type of collection
:::
Create a list of elements of the periodic table (4 of them). These elements are strings.
```python!
elements = ["Hidrogen", "Helium", "Lithium", "Berylium"]
```
Create a list of your five favourite numbers:
```python
favs = [6, 7, 16, 63, 32]
```
Create a list of how many books have you read this year:
```python
booksRead = [0, 5, 4, 4, 4]
```
:::info
Notice that here we have duplicate values and it's ok!
:::
## Indexes and accesses
Ok, so the idea is that we may have different values in our list, like `["apple", "car", "potato"]` but we need a way to access those values. For that, since lists are **ordered** we can retrieve the first, the second or the third element.
Continuing with the favourite numbers
```python
favs = [6, 7, 16, 63, 32]
```
How can we access to the 3rd favourite number? We use the brackets and the NUMBER of the index. Remember that they start with 0 so the index of the 3rd element will be 2.
```python
print(favs[2])
```
### Special index accessing to create sublists
In python (this is uncommon in other programming languages) you can create sub-list (so slices of the original list) using `:` in the brackets of the original one.
```python
print(favs[3])
```
This will return the 4th element (63)
But if I write
```python
print(favs[1:3])
```
This will create a sublist from the second element (index 1) to the 4th (index 3) **not included**. In this case it will be `[7, 16]`
```python
print(favs[:3])
```
This will create a sublist from the first element to the the fourth (index 3) **not included**. In this case it will be `[6,7,16]`.
```python
print(favs[3:])
```
This will create a sublist from the fourth (index 3) included until the end of the list. In this case it will be `[63, 32]`.
### Negative indexes
Python also has another implementation of indexes that allows the developer to access the last element using -1. In other programming languages this would en in an indexOutOfBounds error.
So, if using negative indexes the first element would be - (size of the list).
For example to access the first element of this list we can use several solutions
```python=
b = ["OwO",5,5,7,5]
print(b[0])
print(b[-5])
print(b[-len(b)])
```
This will print 3 times "OwO"
### Deviation range() function
Range is a function that in python we're going to use a lot and is going to return us an iterable (not exactly a set).
If we send to range a number, is going to create an iterable from 0 to that number not including going 1 by one.
So if I write this:
```python=
y =list(range(10))
print(y)
```
It will print `[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]`
If we send 2 numbers, it's going to create an iterable from the first to the second not included. So if we write this
```python=
y =list(range(1,5))
print(y)
```
It will print `[1, 2, 3, 4]`
If we send 3 numbers, the last one will be the 'step'. It's going to go from the first number until the second (not included) adding the 3rd number
```python=
y =list(range(1,5,2))
print(y)
```
It will print `[1, 3]`
:::info
**Breaking a bit**
If you try to do something weird, weird things may happen.
```python=
y =list(range(1,5,2,3))
print(y)
```
This gives you an error because range can only have 3 arguments.
```python=
y =list(range(1,5,-2))
print(y)
```
This is not going to give you an error, just an empty list.
```python=
y =list(range(1,-10,-2))
print(y)
```
This will work and it will print `[1, -1, -3, -5, -7, -9]`
:::
## Common simple methods
### Length of an array: len()
Len is a function that we can send our list and it's going to return a number that is the size of the array. It's very useful and common
```python!=
b = ["OwO",5,5,7,5]
print(len(b))
```
One of the main uses of this is to **traverse an array** that we will cover it later using the indexes.
### append()
```python!=
print(a)
a.append(3)
a.append(2)
a.append(3)
print(a)
```
https://www.w3schools.com/python/ref_list_append.asp
### insert()
Is the same as append but instead of the end we need to specify FIRST the index of the list where our new element is going to be
```python!=
print("Hello, World!")
a = []
print(a)
a.append(3)
a.append(2)
a.insert(1, "potato")
print(a)
```
This will print `Hello, World!
[]
[3, 'potato', 2]`
https://www.w3schools.com/python/ref_list_insert.asp
### remove()
This is going to ask for a **VALUE** and it's going to remove the first element with that value.
```python=
a = [7,5,5,7,5]
a.remove(5)
print(a)
```
This will print `[7,5,7,5]`
https://www.w3schools.com/python/ref_list_remove.asp
### pop ()
This is going to ask for an **INDEX** and it's going to remove the first element with that value.
```python=
a = [7,5,5,7,5]
a.pop(3)
print(a)
```
This will print `[7,5,5,5]`
Here we can also use negative indexes
```python=
a = [7,5,5,7,5]
a.pop(-1)
print(a)
```
This will print `[7,5,5,7]`
https://www.w3schools.com/python/ref_list_pop.asp
### index()
This is going to return the index of the first value that we input
https://www.w3schools.com/python/python_lists_methods.asp
### Others
Here you have other commonly used list methods.
https://www.w3schools.com/python/python_lists_methods.asp
:::warning
:warning:
In the exam they are going to ask you to **implement** algorithms of sorting so probably in the exam you're not going to be able to use "count()", "sort()" or "reverse()". This will be explicit in the exam.
In the Internal you can use them freely.
:::
## Traversing a list
For this we need to explain the for loop in python.
```python=
myList= ["Pipo", "Pepa", "Pepe", "Thomas Jefferson"]
for value in myList:
print(value)
```
Let's break this down a bit.
Line number 1 is going to create the list and assign it to myList.
Line number 2 is a **new** for loop.
For loops in Python they have 2 elements. They go always for something in something(iterable).
In this case we define, create a local variable with the name that we want, in this case `value`. But we can go with `x` or `number` or `fuffly`
Example:
```python=
myList= ["Pipo", "Pepa", "Pepe", "Thomas Jefferson"]
for flufflyFlufflington in myList:
print(flufflyFlufflington)
```
Now, the second part is "in something iterable". That can be a list, a calendar, a set or others, like a range (this very common).
Lastly we have a colon (`:`) that is going to be very important to make it work.
Line number 3 is **indented** so we have a clear vew of what is going to happen inside the loop.
So if we write this
```python=
myList= ["Pipo", "Pepa", "Pepe", "Thomas Jefferson"]
for value in myList:
print("Hi " + value)
print("Bye")
```
This is going to print 4 times Hi (plus the name) and only once "Bye"
### Traversing with an enumerator
Sometimes we not only need the elements but also the index of these numbers.
```python=
myList= ["Pipo", "Pepa", "Pepe", "Thomas Jefferson"]
for index, value in enumerate(myList):
print(index, value)
```
### Simple algorithms that use traversing
These are classic algorithms that they ask in the exams as "basic that you should already know"
#### Sum
```python!=
myList= [5,5,17,1500,0]
#first we create a count/sum variable and assign the value 0
sum = 0
for value in myList:
sum = sum + value
print(sum)
```
```python!=
myList= [5,5,17,1500,0]
#first we create a count/sum variable and assign the value 0
sum = 0
for value in myList:
sum += value
print(sum)
```
#### Average
First we calculate the sum, then we divide by the size of the list. An easy way to access the size is with `len()`
```python!=
myList= [5,5,17,1500,0]
#first we create a count/sum variable and assign the value 0
sum = 0
for value in myList:
sum += value
print(sum/len(myList))
```
#### Median
I know that some of you don't know what this mean yet.
The idea of medians is that you get the value in the middle if the list is sorted.
So for finding it out we would need to sort the array first (or even doing a copy if we want to have the original one for any reason) and access the middle value. In case the the values are even, we find the average between these 2.
One simple implementation (and not complete) would be this.
```python!=
myList= [5,5,17,1500,0]
myList.sort()
medianIndex = len(myList)//2
print(myList[medianIndex])
```
:::info
**Why using `//`?**
We are using `//` instead of `/` because we want to have the integer division. If we use `/` we're going to get a float number _even if the result is a whole number_ and **indexes have to be integers**.
Another solutin would be casting, writing `medianIndex = int(len(myList)/2)` to convert the result into an integer.
:::
There is a more oneliner solution
```python!=
myList= [5,5,17,1500,0]
myList.sort()
print(myList[len(myList)//2])
```
:::info
Medians are useful to spot inequalities. So if the numbers in myLists are wages, the average gives us a number, but it doesn't reflect that most of people doesn't have as much earnings as the one with 1500. So with the median we can get another different value.
:::
Solution with the whole possibilities for the list to be odd or even
:::spoiler
```python!=
myList= [5,3,17,1500,0,4]
myList.sort()
print(myList)
if len(myList)%2 ==1:
medianIndex = len(myList)//2
print(myList[medianIndex])
else:
medianIndex = len(myList)//2
other = medianIndex -1
average = (myList[medianIndex]+myList[other])/2
print(average)
```
:::
#### Minimum/maximum
:::info
What is **minimum** or **maximum**. The smallest of a series of numbers is called a **minimum** and the biggest of a series of number is called a **maximum**.
I have been asked this in an exam so I prefer to put it into the notes.
:::
Both are roughly the same algorithm.
For doing a minimum or a maximum first we create a variable to hold temporary the element that we think is the smaller (or bigger) that will be the first.
Then we're going to compare the all of them and if it's bigger than what we thought it was the biggest number, then we **update** the biggest number.
```python!=
myList = [3,24,5,2,14,5,14,4,1,45,33,2]
max = myList[0]
for number in myList:
if number>max:
max = number
#the loop ends here
print(max)
```
There are other that are the _sorting_ algorithms that we're going to dedicate a specific note on those.
#### Count something that happen in an array
Sometimes we want to count how many times we have something in a list. To do that we need an if and a **counter variable** (count or something similar).
For example, let's count how many numbers in a list ends with five.
```python!=
myList = [3,24,5,2,14,5,14,4,1,45,33,2]
count = 0
for number in myList:
if number % 10 == 5:
count+=1
#the loop ends here
print(count)
```
Count how many times the next element is bigger than the previous
```python=
myList = [3,24,5,2,14,5,14,4,1,45,33,2]
count = 0
for index, value in enumerate(myList):
if index == len(myList)-1:
break
if value < myList[index+1]:
count +=1
print(count)
```
Another solution is using range. We need to loop 1 time less than the number of elements since we want to compare one with the next.
We can use a for x in range(-) to do this. For example, if we do this:
```python=
myList = [3,24,5,2,14,5,14,4,1,45,33,2]
count=0
for index in range(len(myList)-1):
count +=1
print(count)
```
In the end to access the elements, the values, we need to use the indexes using the brackets so the final solution should be this:
```python=
count=0
for index in range(len(myList)-1):
if myList[index] < myList[index+1]:
count +=1
print(count)
```
### Energy values
Based on https://adventofcode.com/2024/day/2
We're having reports of the energy levels of the REACTOR. These levels are numbers that it should be all increasing for each report. A report is a list of numbers. The numbers next to each other cannot be equal
For example, given these lists yo can see in the comment in the line if they are safe or not
```python!
list1 = [1, 3, 4, 6, 732] #safe
list2 = [-1, 3, 3] #not safe, two elements that are the same
list3 = [10, 2] #not safe, decreasing
```
Construct in python a function that prints if a given report (a list of number) returns `True` if the report is safe and `False` if it's not. The name of the function is isSafe.
Solution
:::spoiler
Not solution yet.
:::
#### Output the first element that is not odd.
```python=
myList = [3,24,5,2,14,5,14,4,1,45,33,2]
```
Solution:
```python!=
myList = [3,24,5,2,1,5,12,4,1,45,33,24]
count = 0
for value in myList:
if count == 0:
if value%2 != 1:
count = value
else:
continue
else:
break
print(count)
```
credit D.P.
Not optymal but correct
```python!=
myList = [3,24,5,2,1,5,12,4,1,45,33,24]
for value in myList:
if value%2 == 0:
print(value)
break
```

credit T.K.
Return the last element that is even.
```python=
myList = [3,24,5,2,14,5,14,4,1,45,33,2]
```
One implementation could be doing a loop through the list but instead of going from the 1st to the last we can go from the last to the first. For this we can use `range`
How it would be the range? `range(len(myList)-1,-1,-1)`
if we have a list of 3 elements, we would need to go range(2,-1,-1). The first 2 is because the last index is 2 (length of the list -1), the second -1 is the stop that is NOT INCLUDED, and the last -1 is the step.
```python!=
myList = [3,24,5,2,1,5,12,4,1,45,33,26,33,1,1]
for index in range(len(myList)-1,-1,-1):
if myList[index]%2 == 0:
print(myList[index])
break
```
Other implementation is using negative indexes
```python!=
myList = [3,24,5,2,1,5,12,4,1,45,33,26,33,1,1]
for index in range(len(myList)):
if myList[-(index+1)]%2 == 0:
print(myList[-(index+1)])
break
```
### Do something specific for some elements
Also we can change the elements
We can asign in the loop the new values. For example
#### Rounding numbers
This programa is going to take a list of numbers (floats, decimal numbers) and it's going to round them. If their decimal part is equal or bigger than 0.5 is going to be rounded up and else is going to be rounded down.
```python=
myList = [3.5,24.4,5.6,2]
for index in range(len(myList)):
integerPart = int(myList[index])
if myList[index] - integerPart >= 0.5:
myList[index] = integerPart + 1
else:
myList[index] = integerPart
print(myList)
```
:::warning
In this particular case using a `for value in myList` doesn't work because you need to modify elements in the list. You can use it to create a new list, though.
:::
Another option is to create a new list and append elements, then substitute the list itself.
```python=
myList = [3.5,24.4,5.6,2]
newList = []
for value in myList:
integerPart = int(value)
if value - integerPart >= 0.5:
newList.append(integerPart + 1)
else:
newList.append(integerPart)
myList= newList
print(myList)
```
#### Put a threshold to specific values
We have the reports from before, but some of them are too high, we need to set them as a maximum of 10, so if we have `[1,3,4,13,5]` we need to change it to `[1,3,4,10,5]`
```python=
myList = [1,3,4,13,5]
for index in range(len(myList)):
if myList[index] > 10:
myList[index] = 10
```
#### Parallel lists
We may have more than one lists which their values in the same index refer to the same entity. When that happens we say that those lists are parallel.
```python=
names = [ "Aaron", "Hamid", "Fátima"]
grades = [6,5,7]
```
If we asume that Aaron has a grade 6, Hamid a 5 and Fátima a 7 (good for her) that means that both lists are parallel.
In python is a bit underused this characteristic because how for loops work, but with an enumerator we can print in order all the grades and names
```python=
names = [ "Aaron", "Hamid", "Fátima"]
grades = [6,5,7]
for index, name in enumerate(names):
print(name, grades[index])
```
## Strings as lists
Strings are sequences and they have many things in common with lists. In other programming languages, strings are arrays of characters, one after the other.
You can check more exercises in [String exercises in python](/y_afcRmLQcysv05xlSqRuQ)
### Access
We can use [] to access a specific index of the string
```python=
x = "OwO"
print(x[1])
```
This will print `w` because is the second letter (remember that indexes are zero-based)
We can also use the `:` for making easy slices
```python=
x = "Hello world!"
print(x[:2])
```
This will print `He` since are all the characters before the one with the index 2
### Concatenate
For concatenating strings we can just use the + operand. In other programming languages we can use that or other methods.
```python=
x = "Hello world!"
y = x[0]+x[0]
print(y)
z = x +x
print(z)
```
Examples of concatenation
:::info
Remember that concatenation is not commutative, x +y is not the same that y +x
:::
## Exercises
Construct a list with some specifications
In a school they are going to introduce lockers that are going to have 4 different colours. The first locker (locker number 1) is going to be red, the second blue, the third green and the fourth one yellow. The fifth will be red again and so on.
a. Determine the colour of the locker number 402 [1]
Solution
:::spoiler
blue
:::
b. Construct a script in python that creates a list with the 2000 lockers called `lockers`, being the first one "control" (index 0) and the rest of indexes they will correspond to each locker colour. [3]
:::spoiler
One option is
```python!=
lockers = []
lockers.append("control")
for x in range(1,2001):
if x%4 == 1:
lockers.append("red")
if x%4 == 2:
lockers.append("blue")
if x%4 == 3:
lockers.append("green")
if x%4 == 0:
lockers.append("yellow")
print(lockers)
print(lockers[-1])
```
Also we can use the function lockerColour
```python!=
def lockerColour(x):
if x%4 == 1:
return "red"
if x%4 == 2:
return "blue"
if x%4 == 3:
return "green"
if x%4 == 0:
return "yellow"
lockers = []
lockers.append("control")
for x in range(1,2001):
lockers.append(lockerColour(x))
print(lockers)
print(lockers[-1])
```
:::
### Using functions
In some cases you're going to need to use functions that are given to you. You don't need to define nor implement them. You will need to use them.
We can see the example of this using Severance
### Severance

In Severance the protagonist job is to identify and set aside "scary" numbers. It's job is finding that so we're going to have a function that is called **isScary** that if we send a number is going to return true if it's scary and false if it's not.
Construct a function called countScary() that, given a list of numbers, returns the total count of numbers from that list that are scary using the previously described method.
Solution and then step by step:
```python!
def countScary(numbers):
count = 0
for number in numbers:
if isScary(number):
count +=1
return count
```
Ok, now the process. First we identify that we need to do a function (so we need to go with `def`) and what is going to return (a number) so we can start by writing this
```python!
def countScary( ):
return
```
Now we think if we need any parameters, in this case the problem says that yes, given a list of numbers. They don't say if the list is named `numbers` or `potatos` or `x`, we could give it any name, but I suggest that in this case we use names that make sense in this context, in this case: numbers.
```python!
def countScary(numbers):
return
```
They also say that we have to return SOMETHING, and also since we're returning how many, maybe we need to count, so make sens that we put that we return a variable count.
```python!
def countScary(numbers):
return count
```
If we have a count we need to define it first. A good default value for a counter is 0, then we will modify it. So we put at first and we leave some space that will be where the actual counting happens.
```python!
def countScary(numbers):
count = 0
return count
```
Now we need to count how many stuff happens in a list, so we need to loop (or traverse) that list. So we need a loop. You can use `for index in range(len(numbers))` but I'm going to use the more simple `for number in numbers`. Remember that `number` or `index` can be substituted for other names, but I suggest to use these since are more clear.
```python!
def countScary(numbers):
count = 0
for number in numbers:
#do something
return count
```
But we're not going to count all of them, only the scary ones so we need flow control, an if statement. And inside we're going to set the counter to advance 1 element.
```python!
def countScary(numbers):
count = 0
for number in numbers:
if #some condition:
count +=1
return count
```
The condition is that they need to be scary those numbers. To know that we can use the isScary function defined. It's going to return true if they are scary and false if they are not. So we can use the returned value in the if directly.
```python!
def countScary(numbers):
count = 0
for number in numbers:
if isScary(number):
count +=1
return count
```
Variations
These implementations are ok. In this one we can use the == True to dobule check that we're doing the correct comparasion (maybe we want the false ones)
```python!
def countScary(numbers):
count = 0
for number in numbers:
if isScary(number) == True:
count +=1
return count
```
Using range:
```python!
def countScary(numbers):
count = 0
for index in range(len(numbers)):
if isScary(numbers[index]):
count +=1
return count
```
Using list comprehension (www.w3schools.com/python/python_lists_comprehension.asp) . This is going to create another list with only the elements if they are scary. This is advanced but exists. I don't recommend this in an exam unless you actually are very used to it.
```python!
def countScary(numbers):
sublist = [number for number in numbers if isScary(number)]
return len(sublist)
```
The one liner solution. Of course with list comprehension:
```python!
def countScary(numbers):
return len([number for number in numbers if isScary(number)])
```
If you want to test this witchcraft by yourself you can use this snippet that uses even numbers (since we don't actually have access to isScary in the online interpreter)
```python!
def evenNumbers(numbers):
return len([number for number in numbers if number%2==0])
print(evenNumbers([2,1,2,1,2,4,2]))
```
#### Severance 2 (hasScaryNumbers)
Using the previously described function `isScary()` construct the function hasScaryNumbers that, given a list of numbers is going to return true if any of them is a scary number and false otherwise. You may assume that the list already contains just numbers.
Solution
:::spoiler

credit S. H.
:::
#### Severance 3 (ratios)
Now we want to know the ratio, in percentage of scary numbers of a given list.
For example if the list `[3,34,12,41,32]` has 2 scary numbers, it should output 40%
If the list `[25,3,1,2]` has no scary numbers, it should print 0 %
If the list `[3,232,4]` has only one scary number it should print 33.3%
:::info
If you need help with percentages, you should really revise them. Here is a link https://www.bbc.co.uk/bitesize/topics/zf6pyrd/articles/zcwmk2p#znncg7h
:::
a) Write what should the program output if the list `[252,11,1,0,31]` has 4 scary numbers (this should be one mark)
Solution
:::spoiler
80%
:::
b) Using any of the previously defined functions (isScary, countScary, hasScaryNumbers) construct a code that outputs the percentage of scary numbers the list `numbers` has. (this should be 3-4 marks)
Solution
:::spoiler

credit D.O.
:::
### Vampires
The Vampiric Council of Barcelona is the organization that rules vampires in Barcelona and all Catalonia. They are very old in their implementation of IT and now they need to invoke all members for a special meeting. The IT vampire (Berenguela the thirsty hacker) in the 1970s prepared a very long list (with a length of 5000) to store their names called vampires.
However there is less than 5000 vampires. In the places where there is still no vampire recorded there is recorded “NO-VAMPIRE-YET" in the list.
The IT system records their names in the list once they have been registered as vampires in Barcelona, but if they go elsewhere or they are definetely deceased (from a sunburn, for example) their names are still in the list.
To solve that, Berenguela implemented some functions. If you call the method isActive(name) and it recieves the input the name of a Vampire it will return true if the vampire is still active so it can be called because they didn’t move out Catalonia nor has been definetely deceased. If the method is called with “Berenguela, the thirsty hacker” it will return true. If the method is called with “Nandor, the relentless” it will return false since Nandor left Europe long time ago, and if you called also with “NO-VAMPIRE-YET" it will return false.
A) Construct a code that output how many active vampires are in Barcelona using the previously described method [3]
Solution
:::spoiler

Credit V.S.
:::
There is another function “getAddress(name)” that if receives the name of a vampire it will return their address. Finally there is a function “printInvitation(name, address)” that prints an invitation for the next meeting that requires the name of the vampire and their address.
B) Construct the code that prints all the invitations for the next Council using the methods already described. It should not sent invitations to those that are “NO-VAMPIRE-YET”. [4]
Solution:
Note: This exercise is explicitly about reading and understanding. From previous years these are the difficult ones. Take your time reading it.
### Wizard schools
(based in November 2020)
A wizard school has 100 students. All student names and students IDs are held in two separate lists called wizards_ids and wizards_names.
```!
wizards_ids = [10010,10011, 10012, 10013, 10014, ..., 10109]
wizards_names = ["Pipo", "Pepa", "Pepe", "Herminia", "Rincewind", ... , "Gandulfo"]
```
For example the student `Herminia` has the ID number `10013`
The school offers elective subjects such as potions and explosions, forbidden languages and bussiness management. Each student must choose between these electives.
Three lists, `potions_and_explosions`, `forbidden_languages` and `bussiness_management` are created. When a student chooses one of the electives their ID number is appended to the appropiate list.
For example this could be the content of this 3 list at some point.
```!
potions_and_explosions = [10014,10021,10011,10031]
forbidden_languages = [10032,10034,10025]
bussiness_management = [10109,10014,10025,10021]
```
#### isIn function
The function `isIn(x,subject)` is available, where x is the wizard_id and subject is one of the lists of elective subjects. The method will return `True` if the id number `x` is in the given list subject; `False` otherwise.
For example
isIn(10021, potions_and_explosions) returns `True`
isIn(10021, forbidden_languages) returns `False`
Construct the algorithm for the function `isIn(x,subject)`
Solution
//TO-DO
Note on the solution, there is a one liner solution in python but I also want the other one that traverses the list more manually
:::spoiler

Credit M.V.
:::
#### Clash of classes
The potions and explosions class is going to held a degustation class at the same time that the class of bussiness management class are going to evaluate a case study. The potion teacher would like to know how many students will not be able to atteng his degustation class because they will be in the bussiness managment class.
Construct in python an algorithm that will output the number of students who have chosen both potions and explotions and bussiness managment. The method isIn() should be used in the answer (3 marks)
Solution
//TO-DO
#### Is everybody in?
The school coordinator would like to check whether there are students who have not yet chosen any of the three electives.
Construct in python an algoritm that will output the names of students who have not yet chosen any of the electives. An appropiate message should be displayed if every student has chosen a subject (7 marks)
Solution
```python!
# wizards_names
# wizards_ids
noElectiveStudent = []
for index in range(len(wizards_ids)):
if isIn(wizards_ids[index], potions_and_explotions):
continue
if isIn(wizards_ids[index], forbidden_languages):
continue
if isIn(wizards_ids[index], bussiness_management):
continue
noElectiveStudent.append(index)
if len(noElectiveStudent) == 0:
print("All the students has selected something!")
else:
for index in noElectiveStudent:
print(wizards_names[index])
```
#### Casing study
Just for icing the cake, do you remember what is the type of casing that I've been using in this scenario that is not exactly the same that I use normally?
Solution
:::solution
snake_case
:::
### Trace tables, now with lists!
(inspired by Nov 22 exercise)
Consider this list called countries
| | |
| ----| ----|
| [0] | China |
| [1] | Tailand |
| [2] | Australia |
| [3] | Egypt |
| [4] | Denmark |
Construct a trace table for the following algorithm
```
T = 4
while T >= 0:
B = T%4
print(countries(B))
T = T -1
```
Solution:
//TO-DO
### Second trace table with some variations
Consider this list called countries
| | |
| ----| ----|
| [0] | China |
| [1] | Tailand |
| [2] | Australia |
| [3] | Egypt |
| [4] | Denmark |
Construct a trace table for the following algorithm
```
T = 6
while T >= 0:
B = T %4
print(countries(B))
if T%2 == 0:
T = T - 3
else:
T = T + 1
```
Solution
:::spoiler

credit to Y.C.
:::
### Yet another trace table
(I changed the algorithm)
Consider this one-dimensional array COUNTRIES
| | |
| ----| ----|
| [0] | China |
| [1] | Tailand |
| [2] | Australia |
| [3] | Egypt |
| [4] | Denmark |
Construct a trace table for the following algorithm
```
T = 0
while T < 7:
B = T % 4
print(countries(B))
T = T + 1 + B
```
Solution:
:::spoiler

Credit D.O.
:::
### Audio melodies
This is linked to [Melodies in Arduino](/HSHFqID9Sly6rS534i8L4w)
In a specific list we’re using for playing melodies, the odd values are are referred to the frequency of a sound and the even values are referred to another propiety of that sound. For example [440, 2, 426, -4] refers to a sound whose frequency is 440 and then another one whose frequency is 426. We want to make sure that the list is valid and can be played. A list is valid if their frequencies are 0 (that represents a silence) or a value between 20 and 20000 (both values included).
For example
[440,2,426,-4] is a valid melody since 440 and 426 are valid.
[0,1,420,2,354,-1] is also a valid melody since their frecuencies ar 0,420 and 354.
[10,1, 1000, 8] is NOT valid since 10 is outside the range of valid frecuencies
Construct in python a method called validFrecuency that given a list of numbers is going to return true if all the odd values are in the specified ranges and false otherwise.
//TO-DO
## Reference
https://www.w3schools.com/python/python_lists.asp
https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range
[Arrays in IB Pseudocode](/GOWuknHrTJSBs6NsxEeDOA)
[Collections in IB Computer Science](/jJs5xsoHRjWY3n4eYzL9ZQ)
DNI validator code in javascript
https://gist.github.com/afgomez/5691823