Closure#

Syllabus week 6: Lists#

  • Lists, a list is a sequence of values

  • Understanding sequences, elements, and indexes.

  • Creating lists: enclosing the elements in square brackets

  • List indexing

  • List slicing

  • Lists are mutable

  • The keyword is as identity operator vs. equality operator ==

  • List methods: append(), extend(), pop(), index(), sort(), count(), copy()

  • List operators: + (concatenate) and * (repeat)

  • Difference between modification and reassignment

  • Empty lists

  • Deleting list elements

  • Pure functions and modifier functions.

  • Functions min(), max(), sum(), len() and understanding functions that accept different data types

  • Traversing lists

  • Understanding that modifying the indexing variable does not affect the list

  • Constructor list() i.e. list('hej'), list(range(4))

  • Solving problems that involve custom searches within lists.

Advanced#

Note about the material in Advanced section. The advanced material contains more some additional topics related to the weeks’s content. You are not required to read this material, and none of the exercises or exam questions will rely on this material.

Last week, the advanced material covered Default Parameter Values in functions.

Read this page, the part about Using mutable objects as default argument values in python, to learn why None is a commonly used default value in Python functions.

Advanced 6.1: enumerate and zip#

The functions enumerate and zip are commonly used with lists and loops. They allow you to iterate over multiple lists at the same time. The enumerate function returns both the index and the value of each element in a list. For example:

months = ["January", "February", "March"]
#using range
for i in range(len(months)):
    print(f"Month {i+1} is {months[i]}")
#using enumerate
for i, month in enumerate(months):
    print(f"Month {i+1} is {month}")
Month 1 is January
Month 2 is February
Month 3 is March
Month 1 is January
Month 2 is February
Month 3 is March

The following code shows how zip can be used to iterate over multiple lists at the same time:

names = ["Anne-marie", "Benjamin", "Cirkeline"]
ages = [25, 30, 35]
occupations = ["Engineer", "Doctor", "Artist"]
#using range
for i in range(len(names)):
    print(f"{names[i]} is {ages[i]} years old and works as a {occupations[i]}")
#using zip
for name, age, occupation in zip(names, ages, occupations):
    print(f"{name} is {age} years old and works as a {occupation}")
Anne-marie is 25 years old and works as a Engineer
Benjamin is 30 years old and works as a Doctor
Cirkeline is 35 years old and works as a Artist
Anne-marie is 25 years old and works as a Engineer
Benjamin is 30 years old and works as a Doctor
Cirkeline is 35 years old and works as a Artist

No exercise for this section.

Advanced 6.2: List Comprehension#

List comprehension is a powerful tool that can shorten code significantly and sometimes make it more readable (subjective). For example, consider the code below:

numbers = [1, 2, 3, 4, 5]
squared_numbers = []
for number in numbers:
    squared_numbers.append(number**2)
print(squared_numbers)
[1, 4, 9, 16, 25]

With list comprehension, the code can be shortened to:

numbers = [1, 2, 3, 4, 5]
squared_numbers = [number**2 for number in numbers]
print(squared_numbers)
[1, 4, 9, 16, 25]

Similarly, the following snippets from the preparation material are shown with list comprehension:

weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
# prep version
lengths = []
for weekday in weekdays:
    lengths.append(len(weekday))
print(lengths)
# list comprehension version
lengths = [len(weekday) for weekday in weekdays]
print(lengths)
[6, 7, 9, 8, 6]
[6, 7, 9, 8, 6]
recorded_data = [3.0, 4.2, -1, -1, 2.5, 3.7,-1000]
# prep version
positive_data = []
for value in recorded_data:
    if value > 0:
        positive_data.append(value)
print(positive_data)
# list comprehension version
positive_data = [value for value in recorded_data if value > 0]
print(positive_data)
[3.0, 4.2, 2.5, 3.7]
[3.0, 4.2, 2.5, 3.7]

The if statement in list comprehension can be used to filter out elements that do not meet a certain condition. You can also use if and else the expression before the for. For example:

numbers = [1, 2, 3, 4, 5]
even_or_odd = ["even" if number % 2 == 0 else "odd" for number in numbers]
print(even_or_odd)
['odd', 'even', 'odd', 'even', 'odd']

Rewrite the following example to use list comprehension:

vowels = ['a', 'e', 'i', 'o', 'u']
alphabet = list('abcdefghijklmnopqrstuvwxyz')
consonants = []
for letter in alphabet:
    if letter not in vowels:
        consonants.append(letter)
print(consonants)
['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z']

Advanced 6.3: Sum of Squares#

Write a function sum_of_squares that takes an integer n and returns the sum of the squares of all integers from 1 to n. The function can be written in a single line using list comprehension.

Advanced 6.4: Sum Anything#

Rewrite the function sum_anything, which takes a list of numbers and number-like strings, to use list comprehension. Can you make the function a single line?

def sum_anything(lst):
    total = 0
    for element in lst:
        if type(element) == str:
            total += float(element)
        else:
            total += element
    return total
print(sum_anything([1, 2, "3", "4.5"]))
10.5

Advanced 6.5: Prime Numbers#

Write the following function in a single line using list comprehension:

def is_prime(n):
    p = True
    for i in range(2, n):
        if n % i == 0:
            p = False
    return p

Advanced 6.6: Lists of Zeros#

Use list comprehension to create a list containing n zeros. Write a function zero_list, such that zero_list(5) returns [0, 0, 0, 0, 0].

Write an additional function called zero_list_of_lists such that zero_list_of_lists(2, 3) returns [[0, 0, 0], [0, 0, 0]].

Advanced 6.7: List of Functions#

Almost any object in Python can be stored in a list, including functions. This can be useful if you want to apply a series of functions to a value. For example:

my_list = [1, 2, 3, 4, 5]
for f in [len, min, max, sum]:
    print("f =", f.__name__, ", result =", f(my_list))
f = len , result = 5
f = min , result = 1
f = max , result = 5
f = sum , result = 15

Advanced 6.8: Additional List Methods and Functions#

The insert method can be used to insert an element at a specific index in a list. For example:

rocky_planets = ["mercury", "venus", "mars"]
rocky_planets.insert(2, "earth")
print(rocky_planets)

Notice that, of course the index of all elements after the inserted element will be increased by one.

The remove method can be used to remove the first occurrence of a specific element in a list. For example:

rocky_planets = ["mercury", "venus", "earth", "mars", "jupiter"]
rocky_planets.remove("jupiter")

This method is basically the same as using rocky_planets.pop(rocky_planets.index("jupiter")), but in a more readable way.

During the course, the sort method was used to sort lists, however for cases where you want to sort a list without changing the original list, you can use the sorted function. The sorted function returns a new sorted list, while the sort method sorts the list in place. For example:

numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
sorted_numbers = sorted(numbers)
print("sorted_numbers =", sorted_numbers)
print("numbers =", numbers)

Similarly, the reverse method can be used to reverse a list in place (instead of using my_list.sort(reversed=True)), while the reversed function returns a new reversed list. For example:

numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
reversed_numbers = list(reversed(numbers))
print("reversed_numbers =", reversed_numbers)
print("numbers =", numbers)

A small note about the reversed function: it returns an iterator, which is why we use list(reversed(numbers)) to convert it to a list. Try to remove the list function and see what happens. The difference is similar to that of range(5) and list(range(5)).

The map function can be used to apply a function to all elements in a list. For example:

numbers = [1, 2, 3, 4, 5]
def square(x):
    return x**2
squared_numbers = list(map(square, numbers))
print(squared_numbers)

Sometimes you may want to use a lambda function instead of defining a separate function. The code above can be shortened to:

numbers = [1, 2, 3, 4, 5]
squared_numbers = list(map(lambda x: x**2, numbers))

The lambda function is an anonymous function that can be used for simple operations. The syntax is lambda arguments: expression. For example, the two functions below are equivalent:

def polynomial1(x,a,b,c):
    return a*x**2 + b*x + c
polynomial2 = lambda x,a,b,c: a*x**2 + b*x + c
print(polynomial1(2, 1, 2, 3))
print(polynomial2(2, 1, 2, 3))

No exercise for this section.

Advanced 6.9: Median of a List of Numbers#

Complete the function median to find the median of a list of numbers. The median is the number that is in the middle of a data set if the set is ordered from largest to smallest. The function should take an input numbers and return the median. If the list has an even length, take the average of the two middle values. You should expect the results seen below:

>>> median([1, 5, 2, 4, 3])
3
>>> median([2, 4, 6, 8, 5, 10, 12, 15, 16, 17])
9.0
>>> median([999,4,5,1])
4.5

Advanced 6.10: Pascal’s Triangle#

Pascale’s triangle is a triangle of numbers where each number is the sum of the two numbers directly above it. The first few rows of Pascal’s triangle look like this:

          1
        1   1
      1   2   1
    1   3   3   1
  1   4   6   4   1

Write a function pascals_triangle that takes an integer n as input and displays the first n rows of Pascal’s triangle. Also see if you format the numbers in a nice way when printing a triangle with 2 or 3-digit numbers (up to pascals_triangle(13))