Lab 9: Python Practice
Our goal for lab this week is just to let you get comfortable with Python syntax and loops, as well as showing you how to use Python’s built-in function for sorting lists.
Setting up: Pycharm and pytest
Make sure that pycharm and pytest are both installed and set up. There is a setup guide posted on Campuswire. If you need help or are unsure of setup, please call over a TA.
Make a folder inside of PycharmProjects
(mine is located at c:/Users/Nicole/PycharmProjects
, but yours might be somewhere else) called Labs
(you can name it something else – it doesn’t really matter what it’s called). This is where we will be putting all of our python code for our labs.
Starting from this lab, we recommend creating a python file called lab9.py
(and subsequently lab10.py
, lab11.py
, etc.) inside of the Labs
folder.
Maps and Filters in Python
ATTENTION!!! ALL MUFFINS HAVE BEEN STOLEN FROM THE BLUE ROOM (even the Bran ones…)!!!
This is a serious case, so Sherlock and Watson have been called in to catch the culprit and save the day. Since they’re professional sleuths, they’ve decided that their best plan of action is to pretend to be Brown students and find the thief from the inside. For Sherlock and Watson to believably pass as students, they must first enroll in some classes. Here is a list of the courses that they can enroll in this semester:
course_list = ["CSCI0180", "CSCI0160", "CSCI0220", "CSCI0320",
"CSCI1420", "CSCI1951", "APMA0330", "APMA0350", "APMA1650",
"ENGL0220", "ENGL0510", "CLPS0150", "CLPS0450", "CLPS0900",
"CLPS1360"]
NOTE: To do many of the following problems, you will need to do something called string slicing. String slicing is the Python equivalent of Pyret’s string-substring
, but winds up being a lot more powerful.
Let’s say you have the string str = "Beep!"
. Just like in Pyret, strings in Python are 0-indexed:
- The “B” is at index 0
- The "e"s are at indices 1 and 2
- The “p” is at index 3
- The “!” is at index 4
To access the characters at those indices, use the notation: str[index]
. For example,
>>> str[0]
"B"
>>>str[4]
"!"
If you want to slice a string into a substring of more than one character, use the notation: str[start:end]
where start
represents the first index of the substring (inclusive) and end
represents the last index of the substring (exclusive). For example,
>>> str[0:5]
"Beep!"
>>> str[1:4]
"eep"
>>> str[2:3] # note that this is equivalent to str[2]
"e"
>>> str[2:2] # no characters in range, so this outputs the empty string
""
That’s all you need to know for the lab, but Python has a few additional shortcuts for string slicing that might be useful in the long run:
-
If you leave off the start or end index, Python assumes you want to start at 0 and end at the end of the string:
>>> str[:3] # equivalent to str[0:3]
"Bee"
>>> str[3:] # equivalent to str[3:5]
"p!"
>>> str[:] # equivalent to str[0:5]
"Beep!"
-
Negative numbers let you index from the end of a string
>>> str[-1] # equivalent to str[4]
"!"
>>> str[-5] # equivalent to str[0]
"B"
>>> str[-3:-1] # equivalent to str[2:4]
"ep"
Shelock and Watson got over-excited and have registered for so many courses that they can’t keep track of them anymore! Help them sort through and organize their courses:
-
Write a function dept_courses(dept: str)
that takes in a 4-letter department code and produces a list of all courses in department dept
. Then, write a function course_num(num: str)
that takes in a 4-digit course number and produces a list of all courses with that number (regardless of department).
-
Write a function course_search(dept: str, min: int, max: int)
that takes in a 4-letter department code, a minimum course code, and a maximum course code, and produces a list of all courses in department dept
with numbers between min
and max
.
-
Write a function pretty_print(dept: str)
that takes in a 4-letter department code and prints out the full name of a department followed by all of its courses. Each course should be on a separate line with “-” before the course name.
For example:
>>> pretty_print("CSCI")
Computer Science
- CSCI0180
- CSCI0160
- CSCI1420
- CSCI1951
-
Write a function compare_depts(dept1: str, dept2: str)
that takes in the names of two departments and returns the name of the department that is offering more courses. If both departments are offering the same number of courses, the function should return “equal” (str
). If a department isn’t offering any courses, raise an exception.
For each of the following problems, we have provided you with a set of tests. Copy and paste the tests into your code, and run them to ensure that it behaves as expected.
-
Write a function obscure
that takes a string and replaces certain letters with numbers (a common, but ineffective, password protection technique). Specifically, convert every e (or E) to 3, every i (or I) to 1, and every o (or O) to zero. Write a helper function that takes in a single character and converts it if necessary (and keeps it the same if not).
NOTE: You can use == to compare strings, or check whether a character is in a list (such as [“a”, “A”]) of characters to be treated similarly. To check whether an item is in a list, use an in
expression of the form item in list
.
Tests:
def test_obscure():
assert obscure("hello my name is ELI") == "h3ll0 my nam3 1s 3L1", "lowercase & capital changes"
assert obscure("") == "", "empty string"
assert obscure("what") == "what", "no change"
-
Write a function sorted_increasing
that determines whether a list of numbers is sorted into increasing order.
NOTE: The Boolean type is written as bool
in Python; True
and False
(with first letter capital) are the two boolean values.
HINT: The challenge here is to figure out how to track the previous number in the list. Think about how a variable could help you do that.
Tests:
def test_sorted_increasing():
assert sorted_increasing([1, 2, 3]), "increasing"
assert not(sorted_increasing([3, 2, 1])), "decreasing"
assert not(sorted_increasing([1, 2, 3, 2])), "decrease at end"
-
Write a function first_five_pos
that takes a list and returns a list of the first five positive numbers from the input list.
Tests:
def test_first_five_pos():
assert first_five_pos([1, 3, 5, 7, 9, 11, 13]) == [1, 3, 5, 7, 9], "all pos"
assert first_five_pos([1, 3, 5, 7, 9]) == [1, 3, 5, 7, 9], "exactly five"
assert first_five_pos([]) == [], "empty"
assert first_five_pos([-3, -5, 2, -8, 3]) == [2, 3], "some neg"
As a reminder, to run your tests, you should use the terminal inside of PyCharm and run pytest <filename>
. For example, I am coding in a file called lab9.py
, so I will run pytest lab9.py
to run my tests.
Pytest will run all of my functions that start with test_<func>()
, such as test_first_five_pos()
.
The format of a pytest testing function should follow this template:
def test_<func_name>():
assert <func_name>(<input>) == <expected_output>, "<comment about what is being tested>"
Sorting Lists in Python
Basic sorting
Python has a useful and customizable sorting function that operates on lists. In this section, we will explore how to use it.
The simplest version of the function is sorted(lst: list)
, which takes in a list and sorts it in ascending order.
- Lists of integers are sorted numerically
- Lists of strings are sorted alphabetically
- Lists of booleans are sorted with all Falses before all Trues
For example:
>>> sorted([1,5,3,1])
[1,1,3,5]
>>> sorted(["bc", "abc", "d", "aa", "aaa"])
['aa', 'aaa', 'abc', 'bc', 'd']
>>> sorted([False, True, True, False, True])
[False, False, True, True, True]
To sort a list in descending order, add the input reverse=True
to the function call. Here are the examples from above but sorted in reverse:
>>> sorted([1,5,3,1], reverse=True)
[5,3,1,1]
>>> sorted(["bc", "abc", "d", "aa", "aaa"], reverse=True)
['d', 'bc', 'abc', 'aaa', 'aa']
>>> sorted([False, True, True, False, True], reverse=True)
[True, True, True, False, False]
NOTE: Notation like reverse=True
is used for optional inputs to a function, a concept we did not see in Pyret. Since an optional input might not be provided, we need the <name>=
part to indicate which optional parameter is being used.
Custom sorting
In most cases, default sorting is enough. However, what if you want to sort a list in a specific, custom way? To do so, add the input key=my_fun
where my_fun
represents a function that takes in a single list element. my_fun
is called on each element in the list, and its output determines the sort order.
Let’s take a look at a concrete example. The following function takes in a string and returns its length:
def key_fun(elem: str):
return len(elem)
With key_fun
defined, we can do the following to sort the list by string length:
>>> sorted(["Sherlock", "does", "love", "sorting", "lists"], key=key_fun)
['does', 'love', 'lists', 'sorting', 'Sherlock']
(Note that since string length is an integer, sorted
defaults to sorting the elements in increasing order)
Let’s apply this idea to the course list examples from earlier.
-
Sort course_list
in alphabetical order by department code.
-
Sort courses by course number, regardless of department code.
Sherlock and Watson just signed up to compete in a Mystery-scrabble competition. While they are both excellent detectives, they happen to be very bad at this game and need your help to win. They want to use custom sorting to help them efficiently find the best word. In this version of Scrabble, point values for words are based solely on the length of a word, rather than the letters themselves. Given a list of possible words, they want to know which ones will secure them the most points – so instead of sorting the list alphabetically, they sort the list based on the length of each word in it.
Another way to think about what’s happening is to imagine mapping the key
function on the list, sorting, and then undoing the mapping. In other words:
Step 1 (the original list): [“Sherlock”, “does”, “love”, “sorting”, “lists”]
Step 2 (the mapped list): [8, 41, 42, 7, 5]
Step 3 (the sorted order): [41, 42, 5, 7, 8]
Step 4 (the “un-mapped” list): [“does”, “love”, “lists”, “sorting”, “Sherlock”]
NOTE: Notice that when multiple elements mapped to the same thing (in this case, multiple elements had four letters), they stayed in their original order. This is called stable sorting.
Sherlock and Watson have decided to up the ante by adding some new, more complex, rules to the game. Awarding a point value for a word has been adjusted to the following:
- Vowels (including y): 1 point
- Consonants: 2 points
- Unless the consonant is z/q/x, in which case it is worth 5 points
-
Write a function sort-by-score(lst : list)
that takes in a list of strings and sorts them by their score (in descending order), using the updated scoring system.
For example, “beep” has a score of 2+1+1+2=6 and sort-by-score(["aaa", "aba", "z", "beep", "boop"])
should return ["beep", "boop", "z", "aba", "aaa"]
.
Board Game Night Champs
Sherlock and Watson had a blast at Board Game Night. Needless to say, Mystery-scrabble was a hit, and Sherlock and Watson were declared the champions. They used the custom-sorting functions to win the game and figure out their courseload, and now they’re ready to take on the semester and find the missing muffins!
Lab 9: Python Practice
Our goal for lab this week is just to let you get comfortable with Python syntax and loops, as well as showing you how to use Python’s built-in function for sorting lists.
Setting up: Pycharm and pytest
Make sure that pycharm and pytest are both installed and set up. There is a setup guide posted on Campuswire. If you need help or are unsure of setup, please call over a TA.
Make a folder inside of
PycharmProjects
(mine is located atc:/Users/Nicole/PycharmProjects
, but yours might be somewhere else) calledLabs
(you can name it something else – it doesn’t really matter what it’s called). This is where we will be putting all of our python code for our labs.Starting from this lab, we recommend creating a python file called
lab9.py
(and subsequentlylab10.py
,lab11.py
, etc.) inside of theLabs
folder.Maps and Filters in Python
ATTENTION!!! ALL MUFFINS HAVE BEEN STOLEN FROM THE BLUE ROOM (even the Bran ones…)!!!
This is a serious case, so Sherlock and Watson have been called in to catch the culprit and save the day. Since they’re professional sleuths, they’ve decided that their best plan of action is to pretend to be Brown students and find the thief from the inside. For Sherlock and Watson to believably pass as students, they must first enroll in some classes. Here is a list of the courses that they can enroll in this semester:
NOTE: To do many of the following problems, you will need to do something called string slicing. String slicing is the Python equivalent of Pyret’s
string-substring
, but winds up being a lot more powerful.Let’s say you have the string
str = "Beep!"
. Just like in Pyret, strings in Python are 0-indexed:To access the characters at those indices, use the notation:
str[index]
. For example,If you want to slice a string into a substring of more than one character, use the notation:
str[start:end]
wherestart
represents the first index of the substring (inclusive) andend
represents the last index of the substring (exclusive). For example,That’s all you need to know for the lab, but Python has a few additional shortcuts for string slicing that might be useful in the long run:
If you leave off the start or end index, Python assumes you want to start at 0 and end at the end of the string:
Negative numbers let you index from the end of a string
Shelock and Watson got over-excited and have registered for so many courses that they can’t keep track of them anymore! Help them sort through and organize their courses:
Write a function
dept_courses(dept: str)
that takes in a 4-letter department code and produces a list of all courses in departmentdept
. Then, write a functioncourse_num(num: str)
that takes in a 4-digit course number and produces a list of all courses with that number (regardless of department).Write a function
course_search(dept: str, min: int, max: int)
that takes in a 4-letter department code, a minimum course code, and a maximum course code, and produces a list of all courses in departmentdept
with numbers betweenmin
andmax
.Write a function
pretty_print(dept: str)
that takes in a 4-letter department code and prints out the full name of a department followed by all of its courses. Each course should be on a separate line with “-” before the course name.For example:
Write a function
compare_depts(dept1: str, dept2: str)
that takes in the names of two departments and returns the name of the department that is offering more courses. If both departments are offering the same number of courses, the function should return “equal” (str
). If a department isn’t offering any courses, raise an exception.For each of the following problems, we have provided you with a set of tests. Copy and paste the tests into your code, and run them to ensure that it behaves as expected.
Write a function
obscure
that takes a string and replaces certain letters with numbers (a common, but ineffective, password protection technique). Specifically, convert every e (or E) to 3, every i (or I) to 1, and every o (or O) to zero. Write a helper function that takes in a single character and converts it if necessary (and keeps it the same if not).NOTE: You can use == to compare strings, or check whether a character is in a list (such as [“a”, “A”]) of characters to be treated similarly. To check whether an item is in a list, use an
in
expression of the formitem in list
.Tests:
Write a function
sorted_increasing
that determines whether a list of numbers is sorted into increasing order.NOTE: The Boolean type is written as
bool
in Python;True
andFalse
(with first letter capital) are the two boolean values.HINT: The challenge here is to figure out how to track the previous number in the list. Think about how a variable could help you do that.
Tests:
Write a function
first_five_pos
that takes a list and returns a list of the first five positive numbers from the input list.Tests:
As a reminder, to run your tests, you should use the terminal inside of PyCharm and run
pytest <filename>
. For example, I am coding in a file calledlab9.py
, so I will runpytest lab9.py
to run my tests.Pytest will run all of my functions that start with
test_<func>()
, such astest_first_five_pos()
.The format of a pytest testing function should follow this template:
Sorting Lists in Python
Basic sorting
Python has a useful and customizable sorting function that operates on lists. In this section, we will explore how to use it.
The simplest version of the function is
sorted(lst: list)
, which takes in a list and sorts it in ascending order.For example:
To sort a list in descending order, add the input
reverse=True
to the function call. Here are the examples from above but sorted in reverse:NOTE: Notation like
reverse=True
is used for optional inputs to a function, a concept we did not see in Pyret. Since an optional input might not be provided, we need the<name>=
part to indicate which optional parameter is being used.Custom sorting
In most cases, default sorting is enough. However, what if you want to sort a list in a specific, custom way? To do so, add the input
key=my_fun
wheremy_fun
represents a function that takes in a single list element.my_fun
is called on each element in the list, and its output determines the sort order.Let’s take a look at a concrete example. The following function takes in a string and returns its length:
With
key_fun
defined, we can do the following to sort the list by string length:(Note that since string length is an integer,
sorted
defaults to sorting the elements in increasing order)Let’s apply this idea to the course list examples from earlier.
Sort
course_list
in alphabetical order by department code.Sort courses by course number, regardless of department code.
Sherlock and Watson just signed up to compete in a Mystery-scrabble competition. While they are both excellent detectives, they happen to be very bad at this game and need your help to win. They want to use custom sorting to help them efficiently find the best word. In this version of Scrabble, point values for words are based solely on the length of a word, rather than the letters themselves. Given a list of possible words, they want to know which ones will secure them the most points – so instead of sorting the list alphabetically, they sort the list based on the length of each word in it.
Another way to think about what’s happening is to imagine mapping the
key
function on the list, sorting, and then undoing the mapping. In other words:Step 1 (the original list): [“Sherlock”, “does”, “love”, “sorting”, “lists”]
Step 2 (the mapped list): [8, 41, 42, 7, 5]
Step 3 (the sorted order): [41, 42, 5, 7, 8]
Step 4 (the “un-mapped” list): [“does”, “love”, “lists”, “sorting”, “Sherlock”]
NOTE: Notice that when multiple elements mapped to the same thing (in this case, multiple elements had four letters), they stayed in their original order. This is called stable sorting.
Sherlock and Watson have decided to up the ante by adding some new, more complex, rules to the game. Awarding a point value for a word has been adjusted to the following:
Write a function
sort-by-score(lst : list)
that takes in a list of strings and sorts them by their score (in descending order), using the updated scoring system.For example, “beep” has a score of 2+1+1+2=6 and
sort-by-score(["aaa", "aba", "z", "beep", "boop"])
should return["beep", "boop", "z", "aba", "aaa"]
.Board Game Night Champs
Sherlock and Watson had a blast at Board Game Night. Needless to say, Mystery-scrabble was a hit, and Sherlock and Watson were declared the champions. They used the custom-sorting functions to win the game and figure out their courseload, and now they’re ready to take on the semester and find the missing muffins!