def filter_list(values, min_value=None, max_value=None):
"""Filters a list of numbers to keep only the ones between one or two thresholds.
You need to set at least one of min_value or max_value!
Parameters
----------
values : list
a list of numbers (floats or ints)
min_value : float or int, optional
the minimum threshold to filter the data (inclusive)
max_value : float or int, optional
the maximum threshold to filter the data (inclusive)
Examples
--------
>>> a = [1, 3, 4, 2.2]
>>> filter_list(a, min_value=2)
[3, 4, 2.2]
>>> a # a is unchanged
[1, 3, 4, 2.2]
>>> filter_list(a, max_value=3)
[1, 3, 2.2]
>>> filter_list(a, min_value=2, max_value=3)
[3, 2.2]
>>> filter_list([1, 2, 3, 4])
Traceback (most recent call last):
...
ValueError: Need to set at least one of min_value or max_value!
"""
if min_value is None and max_value is None:
raise ValueError('Need to set at least one of min_value or max_value!')
= []
output
# <your own code here>
return output
Assignment #04
Unit 4
Until the next session, study the provided lecture material and solve the following exercises.
Go back to the program you wrote for the previous exercise #03-04. Make your program code as organised and easy-to-read as possible. To do so, pack the language classification that selects the welcome message into a function welcome_message(name, language)
that you use in the main part of your script.
years2days()
Today we coded a function years2days()
.
- So far, the error message (“traceback”) that we get when providing the function with a different data type other than
int
orfloat
is very cryptic and a user might not learn from the message what they did wrong or why the function fails. Modify the function, so that it prints a meaningful message when the user tries to executeyears2days("ten")
. - So far,
n_leapyears
is simply added to the conversion result. The function would happily execute the statementyears2days(1, n_leapyears=2)
, which is obviously meaningless. Implement a check that prints a message and does not execute the conversion ifn_leapyears
is more thanyears
.
numpy.array_equal()
Earlier we used the function numpy.array_equal
to test whether two arrays had the same shape and same values. Code your own function that does the very same! Test whether your own function and the numpy function yield the same results.
Below, I pasted the skeleton of a function I want you to code. Most importantly, I provide you with the documentation of the function. We read function documentation in the past (using help()
), and we learned how to write the docstrings for our own functions, too. Here, you see a more comprehensive example of a function documentation. Carefully read the documentation and try to understand what the function is supposed to do. The examples help illustrate the information provided by the docstring and the parameter definitions.
- None: We have not yet talked about the
None
keyword, but if you consult the Internet you will quickly see that it is easy to understand. - So far, we have used the
print()
function to craft (“error”) messages to the user. In the function below, I demonstrate you how a “proper” error can be raised.
- You will have to iterate through the provided list of values …
- … and use a well-crafted conditional expression to decide which values …
- … need to be ‘added’ to the output list (find the right function yourself in our classroom material!)
Notebook
For the remaining two exercises, use the opportunity of solving the exercises in a notebook to familiarize yourself with the workflow of creating and deleting cells, writing markdown, and running code in a notebook. Download the file 04E_tasks.ipynb to find a notebook that I prepared for you.
The following exercises are taken from Fabien Maussion’s lecture material to the course Introduction to programming
Below, you will find a code block that reads the contents of the file Stationsliste_20230101.csv line-by-line. (Note, you have to put both the .csv
file and this notebook in the same directory, preferably into 04_unit
, for the code to work.)
# Open the csv file:
with open('Stationsliste_20230101.csv', encoding='latin-1') as file_handle:
# Initialize a variable that counts the number of lines
count = 0
# Iterate through all lines in the csv file
for line in file_handle:
count += 1
line = line.rstrip()
# <your code will go here>
# once you are starting to add your code, you can comment out
# the following three lines that produce the current output:
print(line)
if count > 5:
break
Your task is to extend this code to ignore the first line, and then populate three lists with data: names
, years
, elevations
. The lists contain the data converted to int
and float
s for the lists years
and elevations
. Here is the expected output for the first 5 lines and the list years
(note that you will have to extract the years from the complete date):
>>> years
[2021, 2004, 2007, 2007, 1989]
The lists should contain 278 elements each.
Tip: The string methods .split()
and .replace()
, as well as string slicing, help you achieve that goal.
Now, use the lists you just computed and the function filter_list
you created earlier in exercise #04-05, as well as the python function max()
and the list method index()
to answer the following questions:
- How many stations are located above 2000m?
- What is the highest station elevation, and what is the station’s name?
Solutions
def welcome_message(name, language):
"""
Generate a welcome message based on the chosen language.
"""
if language == "EN":
return f"How's it, {name}!"
elif language == "DE":
return f"Hallo, {name}!"
elif language == "XX":
return f"Greetings, {name}!"
else:
return "Unsupported language. Please choose EN, DE, or XX."
# Prompt the user for their name
name = input("Enter your name: ")
# Prompt the user for their preferred language
language = input("Enter your language (EN, DE, XX): ")
# Call the welcome_message function to generate the welcome message
message = welcome_message(name, language)
# Print the welcome message
print(message)
years2days()
# Note that this solution implements a TypeError (instead of a simple print message),
# which we encountered later in this unit
def years2days(years, n_leapyears=0):
"""
Convert Years to Days
This function takes a number of years as input and calculates
the equivalent number of days.
"""
# Ensure meaningful parameter types
try:
years = float(years)
n_leapyears = int(n_leapyears)
except:
raise TypeError("years needs to be numeric, and n_leapyears needs to be an integer!")
# Ensure meaningful leap year logic
if n_leapyears > years:
print("`n_leapyears` cannot meaningfully be greater than `years`! Returning without result.")
return
else:
# finally, compute the conversion
days = (years * 365) + n_leapyears
return days
numpy.array_equal()
def custom_array_equal(arr1, arr2):
"""
Check whether two numpy arrays are equal
This function aims to implement a custom version of numpy.array_equal() by checking whether
two arrays have the same shape and contain the same values.
"""
bool = (arr1.shape == arr2.shape) and (np.all(arr1 == arr2))
return bool
def filter_list(values, min_value=None, max_value=None):
"""Filters a list of numbers to keep only the ones between one or two thresholds.
You need to set at least one of min_value or max_value!
Parameters
----------
values : list
a list of numbers (floats or ints)
min_value : float or int, optional
the minimum threshold to filter the data (inclusive)
max_value : float or int, optional
the maximum threshold to filter the data (inclusive)
Examples
--------
>>> a = [1, 3, 4, 2.2]
>>> filter_list(a, min_value=2)
[3, 4, 2.2]
>>> a # a is unchanged
[1, 3, 4, 2.2]
>>> filter_list(a, max_value=3)
[1, 3, 2.2]
>>> filter_list(a, min_value=2, max_value=3)
[3, 2.2]
>>> filter_list([1, 2, 3, 4])
Traceback (most recent call last):
...
ValueError: Need to set at least one of min_value or max_value!
>>> filter_list([1, 2, 3, "string"], min_value=2)
Traceback (most recent call last):
...
TypeError: All list elements need to be of type int or float!
>>> filter_list([1, 2, 3, 4], min_value="eins")
Traceback (most recent call last):
...
TypeError: min_value needs to be of type int or float!
"""
# ensure at least one filter threshold has been set
if min_value is None and max_value is None:
raise ValueError('Need to set at least one of min_value or max_value!')
# enforce correct data types of min/max_value
if min_value is not None and not isinstance(min_value, (int, float)):
raise TypeError("min_value needs to be of type int or float!")
if max_value is not None and not isinstance(max_value, (int, float)):
raise TypeError("max_value needs to be of type int or float!")
output = []
# loop through all elements of the list
for element in values:
# enforce correct data types of list elements
try:
element = float(element)
except:
raise TypeError("All list elements need to be of type int or float!")
# check if the element passes the minimum and maximum conditions (if specified)
passes_min = (min_value is None) or (element >= min_value)
passes_max = (max_value is None) or (element <= max_value)
# append numbers that satisfy both conditions to the output list
if passes_min and passes_max:
output.append(element)
return output
# Open the csv file:
with open('Stationsliste_20230101.csv', encoding='latin-1') as fhand:
# Initialize a variable that counts the number of lines
count = 0
# Initialize output lists
names = []
years = []
elevations = []
# Iterate through all lines in the csv file
for line in fhand:
count += 1
line = line.rstrip()
# Ignore first line
if count == 1:
continue
# separate line into individual data columns
columns = line.split(";")
# append name
name = columns[1]
if name[-1] == " ":
name = name[:-1]
names.append(name)
# append year
year = int(columns[6][0:4])
years.append(year)
# append elevation
elev = float(columns[5])
elevations.append(elev)
# once you are starting to add your code, you can comment out
# the following three lines that produce the current output:
# print(line)
# if count > 5:
# break
Alternatively, you can download the notebook I solved for you.