Extra material

Advanced List Indexing

There are a few different ways to access elements in a list. You are already familiar with using an index inside of brackets.

myList = [1, 2, 3, 4, 5, 6, 7]
print(myList[3])
4

You can also use negative indexes. -1 gives to the last element, -2 the second to last and so on.

print(myList[-1])
print(myList[-2])
7
6

You can also use what is called slicing to get only some of the elements of the list. Slicing works like this: myList[from:to] returns all of the elements from index from to index to, not including the element at index to. You can also slice with myList[to:from:step], which does the same thing, but only includes every step elements.

print(myList[1:6])
print(myList[1:6:2])
[2, 3, 4, 5, 6]
[2, 4, 6]

Counting with for loops

To calculate the probability of a favorable event it is often useful to count the number of favorable events and divide it by the total number of possible events.

For instance: What is the probability of rolling two sixes on two dice? There is only one event where the two dices both roll a six, and 36 total possible events (you can roll a 1 and 2, 2 and 1, 6 and 3 and so on), all of which with equal probability. The probability of rolling two sixes is then 1/36.

What is the probability of a well shuffled deck of cards being in order? There is only one permutation of the deck of cards that is shuffeled. But how many total permutations(orderings) are there?

Say you shuffle a deck of cards by picking out one card at a time at random. For your first card you have 52 choices, for the second you have 51 choices and so on until the last card when you have 1 choice. All of these possible choices represent a possible permutation(ordering) of your deck. To count how many there are in total you need to multiply all of these number of choices together. Because for all 52 first choices you have 51 possible second choices, so after just drawing two cards there are 52 * 51 possible choices, and this number increases fast when you draw more cards.

To multiply all of the numbers from 52 to 1 (52 * 51 * 50 * 49 * ... * 3 * 2 * 1) in Python, you can use a for-loop.

permutations = 1
for i in range(1, 53):
    permutations = permutations * i
print(permutations)
80658175170943878571660636856403766975289505440883277824000000000000

This is how many ways you can shuffle a deck of cards. For well shuffled deck to be in order, you need to end up at the one specific ordering out of all of these possible ones.

Let’s move back to dice. How likely are you to roll two numbers that sum up to 7?

To check every possible combination of two dice, you can put a for loop inside another for loop so that for every possible result for dice1, you try out every possible result for dice2.

for dice1 in range(1, 7):
    for dice2 in range(1, 7):
        print(f"Rolled {dice1} and {dice2}")
Rolled 1 and 1
Rolled 1 and 2
Rolled 1 and 3
Rolled 1 and 4
Rolled 1 and 5
Rolled 1 and 6
Rolled 2 and 1
Rolled 2 and 2
Rolled 2 and 3
Rolled 2 and 4
Rolled 2 and 5
Rolled 2 and 6
Rolled 3 and 1
Rolled 3 and 2
Rolled 3 and 3
Rolled 3 and 4
Rolled 3 and 5
Rolled 3 and 6
Rolled 4 and 1
Rolled 4 and 2
Rolled 4 and 3
Rolled 4 and 4
Rolled 4 and 5
Rolled 4 and 6
Rolled 5 and 1
Rolled 5 and 2
Rolled 5 and 3
Rolled 5 and 4
Rolled 5 and 5
Rolled 5 and 6
Rolled 6 and 1
Rolled 6 and 2
Rolled 6 and 3
Rolled 6 and 4
Rolled 6 and 5
Rolled 6 and 6

To make Python do the counting of favorable outcomes for us we need to create a variable that tracks the number of favorable outcomes, and then update that variable whenever the code encounters a favorable outcome.

possible = 0
favorable = 0

for dice1 in range(1, 7):
    for dice2 in range(1, 7):
        possible += 1
        if dice1 + dice2 == 7:
            favorable += 1
print(f"There are {possible} possible throws of two dice")
print(f"There are {favorable} throws of two dice where the dice sum to 7")
print(f"The chance of throwing two dice that sum to 7 is {favorable/possible}")
There are 36 possible throws of two dice
There are 6 throws of two dice where the dice sum to 7
The chance of throwing two dice that sum to 7 is 0.16666666666666666

How likely are you to roll three numbers that sum up to 10?

Now there are way more possibilities to check (6 * 6 * 6 in fact). Luckily, Python can count very quickly. To count and check every possible combination of three dice, you can nest three for loops so that every possible combination of dice is checked.

possible = 0
favorable = 0

for dice1 in range(1, 7):
    for dice2 in range(1, 7):
        for dice3 in range(1, 7):
            possible += 1
            if dice1 + dice2 + dice3 == 10:
                favorable += 1
                
print(f"There are {possible} possible throws of three dice")
print(f"There are {favorable} throws of three dice where the dice sum to 10")
print(f"The chance of throwing three dice that sum to 10 is {favorable/possible}")
There are 216 possible throws of three dice
There are 27 throws of three dice where the dice sum to 10
The chance of throwing three dice that sum to 10 is 0.125