In-Class#

Coding Practice#

Code 6.1: Your Name#

Define a list containing your first, last, and any middle names. For example:

my_name = ["Lars", "Løkke", "Rasmussen"]

Now, print out a message like this, but for your name, using the list you defined:

My first name is Lars and my last name is Rasmussen
In total, I have 3 names.

Ensure that your message works for other names, with a varying number of middle names. Test with the my_name defined above and with a person who has no middle name.

Code 6.2: Powers of 2#

Define an integer variable n. Now create a list containing the first n powers of \(2\). For example, for n = 4, the list should contain the values \(2^1, 2^2, 2^3, 2^4\), so that the list is [2, 4, 8, 16] .

Test your code with n = 1, n = 4, and n = 10.

Code 6.3: Average of a List#

Write a function average that takes a list of numbers as input and returns the average of the numbers in the list. Test it with the list from the previous exercise for n = 4.

>>> average([2, 4, 8, 16])
7.5

Code 6.4: Slicing the Months#

You are given the following list:

months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

Use list slicing to extract the following lists from months. Each can be extracted with a single slice:

  • spring: The list containing ['Mar', 'Apr', 'May']

  • summer: The list containing ['Jun', 'Jul', 'Aug']

  • quarter_starts: The list containing ['Jan', 'Apr', 'Jul', 'Oct'] (every third month starting from January)

  • quarter_ends: The list containing ['Mar', 'Jun', 'Sep', 'Dec'] (every third month starting from March)

  • reversed_months: The list containing the months in reverse order

Now assign the variable winter (equal to ['Dec', 'Jan', 'Feb'] ), where you will need more than just slicing.

Code 6.5: All Months with More than d Days#

Use the months list from the previous exercise along with the following list:

days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

Create a new list, months_with_more_than_d_days, containing the names of all months that have more than d days. For example, for d = 30, the list should contain:

['Jan', 'Mar', 'May', 'Jul', 'Aug', 'Oct', 'Dec']

Try it also for d = 31 and confirm that the list is empty.

Code 6.6: How Many Josh?#

You are given the following list:

names = ['James', 'Julie', 'Josh', 'John', 'Josh', 'Jill', 'Josh', 'Jenny', 'Josh']

Write a single line of code (useing a list method) to find out how many times the string 'Josh' appears in this list.

Code 6.7: Top k Elements#

Create a function top_k that takes a list and an integer k as input. It should return a list containing the k largest elements from the list, in ascending order. You can assume the list has k or more elements. Here are examples of using the function:

>>> top_k([0, -5, 2], 1)
[2]
>>> top_k([6, 6, 2, 25, 1, 999, -5], 3)
[6, 25, 999]

After this, modify your function so that the returned list has the items in descending order.

Code 6.8: Is Available?#

You are given the following list:

menu = ["pasta", "pizza", "salad", "soup", "steak", "chicken", "sandwich"]

Write code that uses the menu list and another variable dish, and assigns is_available to True if it’s possible to order the dish at this restaurant, or False if it’s not. For example, dish = "pasta" should assign True, and dish = "burger" should assign False.

Now, write a function which_available that takes two lists, menu and desired_dishes, and returns a list of booleans indicating which of the desired dishes are available. For example:

>>> menu = ["pasta", "pizza", "salad", "soup", "steak", "chicken", "sandwich"]
>>> which_available(menu, ["salad", "beer", "pasta", "hotdog", "dog"])
[True, False, True, False, False]
>>> which_available([], ["salad"])
[False]

Problem Solving#

Problem 6.9: First Alarm#

The water level of a river is measured (in meters) and recorded every hour. An alarm is triggered if one or more of the following two conditions are met:

  • The water level has risen by more than 0.2 meters during the last hour, and the resulting water level is higher than 1.5 meters. Note that you cannot measure this change for the very first measurement.

  • The water level is above 2.0 meters.

The water level measurements are stored in a list. Your task is to write a function that returns the index of the measurement that raised the first alarm. If no alarm is triggered, the function should return -1. All inequalities are strict (<), so a water level of exactly 2.0 meters is not enough to trigger an alarm.

Here are examples of using the function:

>>> first_alarm([1.52, 1.29, 1.18, 1.45, 1.63, 1.81, 1.95, 2.11, 2.09, 1.98, 1.30])
7

The increase in water level between two consecutive hours is strictly greater than 0.2 meters only between measurements at index 2 and 3. However, the resulting water level at index 3 is not strictly above 1.5 meters, so no alarm is triggered there. An alarm is triggered at index 7 because the water level is strictly above 2.0 meters. Thus, the function returns 7.

The function should have the following specifications:

first_alarm(water_levels)

Return the index of the first alarm given the list of water levels.

Parameters:

  • water_levels

list of float

A list of water levels.

Returns:

  • int

The index at which the alarm is triggered. Returns -1 if no alarm is triggered.

You can also use these additional tests for your function:

Hide tests
tests = []
def test_first_alarm(water_levels, expected):
    result = first_alarm(water_levels)
    if result != expected:
        print("Water levels", water_levels, "should give", expected, "but gave", result)
    return result == expected
tests.append(test_first_alarm([1.01, 1.44, 1.32, 1.60, 1.74, 1.44, 1.55, 1.83, 2.04, 2.34], 3))
tests.append(test_first_alarm([1.52, 1.43, 1.42, 1.58, 1.74, 1.44], -1))
tests.append(test_first_alarm([2.01, 1.99, 2.5], 0))
tests.append(test_first_alarm([1.34], -1))
if all(tests):
    print("All tests passed")

Problem 6.10: Unique Items in List#

Write a function unique_values that takes as input a list and returns a new list that only contains unique values. That is, each item only appears once in the returned list. The elements in the returned list should be in the order they first occur in the input list. You should not modify the input list.

Here are a few examples of using the function:

>>> RNA = list("AGGCUUAAUCCG")
>>> unique_values(RNA)
['A', 'G', 'C', 'U']
>>> RNA # check that the original list is not changed
['A', 'G', 'G', 'C', 'U', 'U', 'A', 'A', 'U', 'C', 'C', 'G']
>>> unique_values(['Fr', 'Fr', 'Sa', 'Su', 'Sa', 'Sa', 'Su', 'Su', 'Mo', 'Fr', 'Sa', 'Fr'])
['Fr', 'Sa', 'Su', 'Mo']
>>> unique_values([1, 2, 20, 6, 210, 20, 2])
[1, 2, 20, 6, 210]

The function should have the following specification:

unique_values(input_list)

Returns a list of unique values from the input list.

Parameters:

  • input_list

list

The list from which to extract unique values.

Returns:

  • list

The unique values from the input list, in the order they first appear.

Problem 6.11: How Many Items Can You Buy?#

You are shopping at a store, and you want to buy as many items as possible without exceeding your budget. Your strategy for doing this is to buy the cheapest items first, only buying the next item if you can afford it. You keep shopping until you can’t afford the next item.

The function gets two inputs: a list of prices of items in the store, and your budget.

Here is an example of using the function:

>>> buy_max_items([1, 3, 2, 5, 4], 7)
3

Try to test the function with test_buy_max_items.py.

The function should have the following specification:

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
Cell In[29], line 1
----> 1 print_docstring(buy_max_items)

File /builds/pgcs/programmering/pg_cs/utils/print_docstring.py:88, in print_docstring(func)
     87 def print_docstring(func):
---> 88     display_markdown(autofunction_md(func))

File /builds/pgcs/programmering/pg_cs/utils/print_docstring.py:49, in autofunction_md(func, wrap_div)
     47 def autofunction_md(func, wrap_div=True):
     48     doc = docstring_parser.parse(func.__doc__)
---> 49     perform_checks(func, doc)
     50     signature_args = "(" + ', '.join([f"{p.arg_name}" for p in doc.params]) + ")"
     51     signature = f"{func.__name__}{signature_args}"

File /builds/pgcs/programmering/pg_cs/utils/print_docstring.py:30, in perform_checks(func, doc)
     28 func_args = [arg.arg for arg in tree.body[0].args.args]
     29 if source != source_dedent:
---> 30     assert func_args[0] == 'self', f"First argument of method is not 'self', but {func_args[0]}."
     31     func_args = func_args[1:]
     32 # check if all arguments are in doc and have the same names

AssertionError: First argument of method is not 'self', but prices.

Problem 6.12: Duplicate Elements#

Write a function duplicate_elements that takes a list and an integer and returns a new list with each element repeated dup times sequentially.

Here is an example of using the function:

>>> duplicate_elements([4, "B", 3.9], 3)
[4, 4, 4, 'B', 'B', 'B', 3.9, 3.9, 3.9]

The function should have the following specification:

duplicate_elements(elements, dup)

Duplicate each element in the list dup times.

Parameters:

  • elements

list

The list of elements to duplicate.

  • dup

int

The number of times to duplicate each element.

Returns:

  • list

The list with each element duplicated dup times.

Problem 6.13: Is the Die Fair?#

You want to check if a die is fair. You have a list of integers from 1 to 6, each integer representing the outcome of the die being rolled.

How we determine if the die is fair depends on the number of rolls we have:

  • If we have 12 or more rolls, the die is fair if the most commonly rolled number is rolled less than a third of the time.

  • If we have fewer than 12 rolls, the die is fair if the most commonly rolled number is rolled 5 times or fewer.

Write a function is_fair_die in a file called is_fair_die.py that takes a list of integers as input and returns True if the die is fair and False otherwise.

In order to test your function, we have supplied test_is_fair_die.py

The function specifications are:

is_fair_die(rolls)

Determines if a die is fair based on the given rolls.

Parameters:

  • rolls

list of int

The outcomes rolls of the die

Returns:

  • bool

If the die is considered fair.

Problem 6.14: Water Height#

The height of the water in a pond changes daily, governed by two factors: the constant decrease in height due to the water outflow and the variable increase in height due to the rain. Given the water height for one day and the rain value, the water height for the next day can be computed as:

\[ h_{\text{today}} = h_{\text{yesterday}} + r - 2 \]

where \(h_{\text{today}}\) is the water height today, \(h_{\text{yesterday}}\) is the water height yesterday, and \(r\) is the rainfall for that day. The water height cannot be negative, so if the computed value is negative, the water height is set to zero.

Write a function water_height that takes as input an integer that describes the initial water height and a list of numbers representing the rainfall for each day, and returns the water height on the final day. Consider the following examples:

>>> water_height(0, [1])
0
>>> water_height(0, [4, 2, 3])
3
>>> water_height(5, [1, 0, 2, 1])
1

The function should have the following specification:

water_height(h0, rain_per_day)

Calculate the final water height after multiple days of rain.

Parameters:

  • h0

float

Initial height of the water in the reservoir.

  • rain_per_day

list of float

List of daily rainfall amounts.

Returns:

  • float

Final height of the water after accounting for daily rainfalls and evaporation.

Problem 6.15: Special Occurrence#

Given a sequence of positive integers, we want to find what we call a special occurrence. A special occurrence is when the number 5 is followed by two numbers where exactly one is 7. Thus the occurrence …5, 3, 7… is a special occurrence, and so is the occurrence …5, 7, 8…, while …5, 7, 7… is not a special occurrence.

Write a function that takes as input a list of positive integers. The function should return the index of the number 5 in the first special occurrence. If no such occurrence exists, the function should return -1.

As an example, consider the input:

>>> special_occurrence([2, 8, 11, 3, 12, 5, 7, 7, 11, 3, 12, 5, 2, 7, 5, 7, 2, 6])
11

The number 5 occurs three times in the sequence, at positions with index 5, 11, and 14. The first occurrence of the number 5 is not a special occurrence as it is followed by two 7s. The second occurrence is a special occurrence as it is followed by 2 and 7. The third occurrence is also a special occurrence, but it occurs later than the second occurrence. Therefore, the function should return 11.

The function should have the following specifications:

special_occurrence(sequence)

Find the first special occurrence in a sequence.

Parameters:

  • sequence

list

A list of positive integers with 0 or more elements.

Returns:

  • int

The index of the first 5 followed by two numbers where exactly one of them is 7.

Returns -1 if no such occurrence is found.