OPS445 Lab 4: Difference between revisions
No edit summary |
|||
Line 72: | Line 72: | ||
'''Sample Run 1:'''<syntaxhighlight lang="bash"> | '''Sample Run 1:'''<syntaxhighlight lang="bash"> | ||
./ lab3e.py | ./lab3e.py | ||
[100, 200, 300, 'six hundred'] | [100, 200, 300, 'six hundred'] | ||
100 | 100 |
Revision as of 19:11, 30 January 2025
!!!THIS LAB IS NOT READY YET!!!
In this lab you will learn about some non-trivial data structures commonly used in Python programming: lists, tuples, sets, and dictionaries.
Lists
A List is a non-trivial data-type in Python. You define a list using a series of comma separated values found between square brackets. Values in a list can be anything: strings, integers, objects, even other lists.
It is important to realise that although lists may appear very similar to arrays in other languages, they are different in a number of aspects including the fact that they don't have a fixed size.
- Create a new Python file for testing things in this section.
- Create three lists with different values: list1 contains only integers, list2 contains only strings, list3 contains a combination of both integers and strings
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9] list2 = ['uli101', 'ops235', 'ops335', 'ops435', 'ops535', 'ops635'] list3 = ['uli101', 1, 'ops235', 2, 'ops335', 3, 'ops435', 4, 'ops535', 5, 'ops635', 6]
The simplest way to access individual elements in a list is using the list index.
The index is a number starting from 0 to (number_of_items - 1). The index of the first element is 0.
- Inspect specified elements in your lists:
print(list1[0]) # First element in list1 print(list2[1]) # Second element in list2 print(list3[-1]) # Last element in list3
- You can also retrieve ranges of items from a list (these are called slices):
print(list1[0:5]) # Starting with index 0 and stopping before index 5 print(list2[2:4]) # Starting with index 2 and stopping before index 4 print(list3[3:]) # Starting with index 3 and going to the end
- Create a Python program called: ~/ops435/lab4/lab3e.py
The program will have a number of functions which output various parts of a list. Each function will return either a single item from the list OR will create a new list and return the entire new list.
- Start with this template:
#!/usr/bin/env python3 # Create the list called "my_list" here, not within any function defined below. # That makes it a global variable. We'll talk about that in another lab. def give_list(): # Does not accept any arguments # Returns all of the global variable my_list unchanged def give_first_item(): # Does not accept any arguments # Returns a single string that is the first item in the global my_list def give_first_and_last_item(): # Does not accept any arguments # Returns a list that includes the first and last items in the global my_list def give_second_and_third_item(): # Does not accept any arguments # Returns a list that includes the second and third items in the global my_list if __name__ == '__main__': # This section also referred to as a "main code" print(give_list()) print(give_first_item()) print(give_first_and_last_item()) print(give_second_and_third_item())
- Here's what you need to do:
- The script should declare a list called my_list created BEFORE any function definition
- The list called my_list should have the values: 100, 200, 300, and "six hundred"
- The script should implement the empty functions - i.e. you have to fill in the bodies for these functions
Sample Run 1:
./lab3e.py
[100, 200, 300, 'six hundred']
100
[100, 'six hundred']
[200, 300]
Sample Run 2 (with import from another script):
import lab3e
lab3e.give_list()
# Will print [100, 200, 300, 'six hundred']
lab3e.give_first_item()
# Will print 100
lab3e.give_first_and_last_item()
# Will print [100, 'six hundred']
lab3e.give_second_and_third_item()
# Will print [200, 300]
- Download the checking script and check your work:
cd ~/ops435/lab4/ pwd #confirm that you are in the right directory ls CheckLab4.py || wget http://ops345.ca/ops445/CheckLab4.py python3 ./CheckLab4.py -f -v lab3e
- Before proceeding, make certain that you identify any and all errors in lab3e.py. When the checking script tells you everything is OK - proceed to the next step.
Manipulating items in lists
There is a number of ways to obtain information about lists as well as change the data that is contained within a list. In this section, you will learn how to manipulate lists.
- Let's perform a simple change to a list element. Try the following code in a temporary python file:
courses = ['uli101', 'ops235', 'ops335', 'ops435', 'ops535', 'ops635'] print(courses[0]) courses[0] = 'eac150' print(courses[0]) print(courses)
- Below are some examples of using built-in functions to manipulate lists. Take your time to see how each function can be a useful tool for making changes to existing lists:
courses.append('ops235') # Add a new item to the end of the list print(courses) courses.insert(0, 'hwd101') # Add a new item to the specified index location print(courses) courses.remove('ops335') # Remove first occurrence of value print(courses) sorted_courses = courses.copy() # Create a copy of the courses list sorted_courses.sort() # Sort the new list print(courses) print(sorted_courses)
- In addition to using functions to manipulate lists, there are functions that are useful to provide information regarding the list such as number of elements in a list, the smallest value and largest value in a list:
list_of_numbers = [ 1, 5, 2, 6, 8, 5, 10, 2 ] length_of_list = len(list_of_numbers) # Returns the length of the list smallest_in_list = min(list_of_numbers) # Returns the smallest value in the list largest_in_list = max(list_of_numbers) # Returns the largest value in the list # Notice how the long line below is wrapped to fit on one editor screen, so you don't need to scroll to read it: print("List length is " + str(length_of_list) + ", smallest element in the list is " + str(smallest_in_list) + ", largest element in the list is " + str(largest_in_list))
Iterating over a list using the for loop
This last section demonstrates a quick and easy way to loop through every value in the list. For loops have a set number of times they loop. The for loop will execute all indented code for each item (element) in the list.
Other programming languages that have a loop such as this: it is usually called a "foreach" loop.
The following for loop's body will execute as many times as there are elements in the list_of_numbers. For each element: it will store its value in a variable named item; and run code indented below.
- Create a temporary Python file with these contents and run it:
list_of_numbers = [1, 5, 2, 6, 8, 5, 10, 2] for item in list_of_numbers: print(item)
- As you can see: instead of writing eight function calls for each element of the list, we can call the print() function in a loop. And we won't have to rewrite code if the length of the list changes.
- Run the following code:
list_of_numbers = [1, 5, 2, 6, 8, 5, 10, 2] def square(num): return num * num for value in list_of_numbers: print(square(value))
The code above only prints the squares and does not save them for future use. The next example uses a function that loops through list, squares the values, and also saves the squares in a new list.
- Run the following code:
list_of_numbers = [1, 5, 2, 6, 8, 5, 10, 2] # Squares each item in a list of numbers, returns new list with squared numbers def square_list(number_list): new_list = [] for number in number_list: new_list.append(number * number) return new_list new_list_of_numbers = square_list(list_of_numbers) print(list_of_numbers) print(new_list_of_numbers)
The above is just one example of a quick use of for loops mixed with lists. But be careful when passing lists into functions. When you give a function a list as an argument, it is the actual list reference and NOT a copy. This means a function can change the list without making a new list. While you do have to be careful, this can also be useful. A function can modify any given list without having to return it.
- To demonstrate, run the following code:
list_of_numbers = [ 1, 5, 2, 6, 8, 5, 10, 2 ] def delete_numbers(numbers): numbers.remove(5) numbers.remove(6) numbers.remove(8) numbers.remove(5) delete_numbers(list_of_numbers) print(list_of_numbers)
Practice with Functions, Lists, and Loops
- Create the ~/ops435/lab4/lab3f.py script. The purpose of this script is to use functions to modify items inside a list.
- Start with this:
#!/usr/bin/env python3 # Place my_list below this comment (before the function definitions) def add_item_to_list(ordered_list): # Appends new item to end of list with the value (last item + 1) def remove_items_from_list(ordered_list, items_to_remove): # Removes all values, found in items_to_remove list, from my_list # Main code if __name__ == '__main__': print(my_list) add_item_to_list(my_list) add_item_to_list(my_list) add_item_to_list(my_list) print(my_list) remove_items_from_list(my_list, [1,5,6]) print(my_list)
- Complete the program following these requirements:
- The missing list should have the values: 1, 2, 3, 4, 5
- The program should have a function called add_item_to_list(ordered_list). This function takes a single argument which is expected to be of type list. The function will retrieve the value of the last item in the list, and it will append a new value to that list so that the new value is one unit bigger than the previous last element.
- The add_item_to_list() function will modify the list it receives via the parameter, and will not return anything.
- The program should have a function called remove_items_from_list(ordered_list, items_to_remove). This function takes two arguments: a list, and a second list of numbers to remove from the first list. For each item in the second list the function will check if that item exists in the first list, and if it exists: remove it.
- The remove_items_from_list() function will modify the ordered_list without returning any value.
Sample Run 1:
run lab3f.py
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6, 7, 8]
[2, 3, 4, 7, 8]
Sample Run 2 (with import):
from lab3f import * print(my_list)
# Will print [1, 2, 3, 4, 5]
add_item_to_list(my_list)
add_item_to_list(my_list)
add_item_to_list(my_list)
print(my_list)
# Will print [1, 2, 3, 4, 5, 6, 7, 8]
remove_items_from_list(my_list, [1,5,6])
print(my_list)
# Will print [2, 3, 4, 7, 8]
- Download the checking script and check your work. Enter the following commands from the bash shell.
cd ~/ops435/lab3/ pwd # confirm that you are in the right directory ls CheckLab4.py || wget http://ops345.ca/ops445/CheckLab4.py python3 ./CheckLab4.py -f -v lab3f
- Before proceeding, make certain that you identify any and all errors in lab3f.py. When the checking script tells you everything is OK - proceed to the next step.
Tuples
Many often confuse a tuple with a list (which you learned about in a previous lab). A tuple is a type of list whose values cannot be changed. Nothing in a tuple can be changed after it's created.
There are some advantages to using tuples for certain purposes:
- Data protection (eg. values are are NOT allowed to change so you won't modify them accidentally)
- Tuples can be used as keys in data dictionaries (which are NOT allowed to change)
- Tuples allow for faster access than lists
The term to indicate that a data structure cannot be changed is immutable (as opposed to "mutable" which means the data structure can be changed).
- Create two tuples in a temporary Python file, so we can learn how to use them and learn how they differ from lists. Note that tuples are defined by using parenthesis ( ) as opposed to lists which are defined by using square brackets [ ]
t1 = ('Prime', 'Ix', 'Secundus', 'Caladan') t2 = (1, 2, 3, 4, 5, 6)
- Values from a tuple can be retrieved in the same way as a list. For example:
print(t1[0]) print(t2[2:4])
- You can also check to see whether a value exists inside a tuple or not. To demonstrate try:
print('Ix' in t1) print('Geidi' in t1)
Let's now see how a tuple differs from a list.
- Create a list:
list2 = ['uli101', 'ops235', 'ops335', 'ops435', 'ops535', 'ops635']
- See if you can change the value of an item in your list:
list2[0]= 'ica100' print(list2[0]) print(list2)
You should have been successful in changing the value of your list.
- Now try changing a value in your previously-created tuple:
t2[1] = 10
Did it work? Once created the tuple values will not be able to change.
If you would like a tuple with different values than the tuple you currently have, then you must create a new one.
- The following creates a new tuple (t3) with a contents from a slice of the t2 tuple. Slicing works the same way for tuples as for lists:
t3 = t2[2:3]
- Also, as with lists, you can use for loops to iterate the values of tuples:
for item in t1: print('Item: ' + item)
Sets
A set has similar characteristics as a list, but there are two major differces:
- Sets are un-ordered
- Sets cannot contain duplicate values
Since new duplicate entries will be automatically removed when using sets, they are useful for performing tasks such as comparisons: finding similarities or differences in multiple sets.
- Create some sets to work with in a new temporary Python file:
s1 = {'Prime', 'Ix', 'Secundus', 'Caladan'} s2 = {1, 2, 3, 4, 5} s3 = {4, 5, 6, 7, 8}
Note: Sets are defined by using curly brackets { } as opposed to tuples which use parenthesis ( ), or lists which use square brackets [ ]
- Try to access a set using an index:
print(s1[0])
This will cause an error. You cannot access data inside a set this way because the elements inside are unordered.
- Instead, you should use the in method to check to see whether a value is contained in the set:
print('Ix' in s1) print('Geidi' in s1)
Sets can be combined, but any duplicate values (shared among sets) will be deleted.
- Print the contents of the sets and note the values that are common:
print(s2) print(s3)
- This is how you get a set containing only unique values (no duplicates) from both sets:
print(s2 | s3) # returns a set containing all values from both sets print(s2.union(s3)) # same as s2 | s3
Notice that both methods above have the same result, which one you choose depends purely on your style.
Instead of combining sets, we can display values that are common to both sets. This is known in mathematical terms as an intersection between the lists.
- Try this:
print(s2 & s3) # returns a set containing all values that s2 and s3 share print(s2.intersection(s3)) # same as s2 & s3
Sets can also have their values compared against other sets. First find out what items are in s2 but not in s3. This is also called a difference.
- Try this:
print(s2) print(s3) print(s2 - s3) # returns a set containing all values in s2 that are not found in s3 print(s2.difference(s3)) # same as s2 - s3
In order to see every difference between both sets, you need to find the symmetric difference.
- This will return a set that shows all numbers from both sets which are not shared:
print(s2 ^ s3) # returns a set containing all values from both sets which are not shared print(s2.symmetric_difference(s3)) # same as s2 ^ s3
The set() function can convert lists into sets, and the list() function can convert sets into lists. The operations in this section can only be applied to sets, so if you need to perform a union, intersection, or difference between lists, you need to convert them to sets first.
- Try this for example:
l2 = [1, 2, 3, 4, 5] l3 = [4, 5, 6, 7, 8] temporary_set = set(l2).intersection(set(l3)) new_list = list(temporary_set) # '''set()''' can make lists into sets. '''list()''' can make sets into lists. print(new_list)
Comparing Sets
- Create the ~/ops435/lab4/lab4a.py program. The purpose of this program will be to demonstrate different ways of comparing sets. There will be three functions, each returning a different set comparison.
- Use the following template to get started:
#!/usr/bin/env python3 def join_sets(s1, s2): # join_sets will return a set that contains every value from s1 and from s2 def match_sets(s1, s2): # match_sets will return a set that contains all values found in both s1 and s2 def diff_sets(s1, s2): # diff_sets will return a set that contains all different values which are not shared between the sets if __name__ == '__main__': set1 = set(range(1,10)) set2 = set(range(5,15)) print('set1: ', set1) print('set2: ', set2) print('join: ', join_sets(set1, set2)) print('match: ', match_sets(set1, set2)) print('diff: ', diff_sets(set1, set2))
- Modify the program so that:
- The join_sets() function returns a set that contains all values from both sets.
- The match_sets() function should return a set that contains all values found in both sets.
- The diff_sets() function should return a set that contains all values which are not shared between both sets.
- All three functions should accept two arguments both of which are sets.
- The program should show the exact output as the samples.
Sample Run 1:
./lab4a.py
set1: {1, 2, 3, 4, 5, 6, 7, 8, 9}
set2: {5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
join: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
match: {8, 9, 5, 6, 7}
diff: {1, 2, 3, 4, 10, 11, 12, 13, 14}
Sample Run 2 (with import):
import lab4a
set1 = {1,2,3,4,5}
set2 = {2,1,0,-1,-2}
print(lab4a.join_sets(set1,set2))
# Will output {-2, -1, 0, 1, 2, 3, 4, 5}
print(lab4a.match_sets(set1,set2))
# Will output {1, 2}
print(lab4a.diff_sets(set1,set2))
# Will output {-2, -1, 0, 3, 4, 5}
- Download the checking script and check your work. Enter the following commands from the bash shell:
cd ~/ops435/lab4/ pwd #confirm that you are in the right directory ls CheckLab4.py || wget http://ops345.ca/ops445/CheckLab4.py python3 ./CheckLab4.py -f -v lab4a
- Before proceeding, make certain that you identify all errors in lab4a.py. When the checking script tells you everything is OK - proceed to the next step.
Comparing Lists
- Create the ~/ops435/lab4/lab4b.py program. This program will improve the previous program to perform the same joins, matches, and diffs, but this time on lists.
- Use the following as a template:
#!/usr/bin/env python3 def join_lists(l1, l2): # join_lists will return a list that contains every unique value from l1 and from l2 def match_lists(l1, l2): # match_lists will return a list that contains all values found in both l1 and l2 def diff_lists(l1, l2): # diff_lists will return a list that contains all different values, which are not shared between the lists if __name__ == '__main__': list1 = list(range(1,10)) list2 = list(range(5,15)) print('list1: ', list1) print('list2: ', list2) print('join: ', join_lists(list1, list2)) print('match: ', match_lists(list1, list2)) print('diff: ', diff_lists(list1, list2))
- Modify the template so that:
- The match_lists() function returns a list that contains all values found in both lists.
- The diff_lists() function returns a list that contains all values which are not shared between both lists.
- The join_lists() function returns a list that contains all values from both lists.
- All three functions should accept two arguments both of which are lists.
- The program should show the exact output as the samples.
Sample Run 1:
./lab4b.py
list1: [1, 2, 3, 4, 5, 6, 7, 8, 9]
list2: [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
join: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
match: [5, 6, 7, 8, 9]
diff: [1, 2, 3, 4, 10, 11, 12, 13, 14]
Sample Run 2 (with import) under interactive python shell:
import lab4b
list1 = [1,2,3,4,5]
list2 = [2,1,0,-1,-2]
print(lab4b.join_lists(list1,list2)))
# Will output [0, 1, 2, 3, 4, 5, -2, -1]
print(lab4b.match_lists(list1,list2))
# Will output [1, 2]
print(lab4b.diff_lists(list1,list2))
# Will output [0, 3, 4, 5, -2, -1]
- Download the checking script and check your work. Enter the following commands from the bash shell.
cd ~/ops435/lab4/ pwd #confirm that you are in the right directory ls CheckLab4.py || wget http://ops345.ca/ops445/CheckLab4.py python3 ./CheckLab4.py -f -v lab4b
- Before proceeding, make certain that you identify all errors in lab4b.py. When the checking script tells you everything is OK - proceed to the next step.
Dictionaries
In Python, a dictionary is a set of key-value pairs. Dictionaries are unordered like sets, however any value can be retrieved from a dictionary if you know the key. This section will go over how to create, access, and change dictionaries, giving you a new powerful tool to store and manipulate data.
- Let's begin by creating a new dictionary in a temporary Python file:
dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Postal Code': 'M3J3M6'}
You should note that the syntax to define a dictionary is similar to defining sets (i.e. using {}), but unlike sets dictionaries use key:value
pairs within the dictionary. Each key:value pair is separated by commas.
- All the keys within a dictionary can be retrieved using the dictionary.keys() function:
print(dict_york.keys())
- All the values in a dictionary can be retrieved in one go by using the dictionary.values() function. This particular function provides a list containing all values:
print(dict_york.values())
- We can retrieve individual values from a dictionary by providing the key associated with the value:
print(dict_york['Address']) print(dict_york['Postal Code'])
- Dictionary keys can be any immutable values (i.e. not permitted for value to be changed). Types of values include: strings, numbers, and tuples.
- Try adding a new key and value to the dictionary:
dict_york['Country'] = 'Canada' print(dict_york) print(dict_york.keys()) print(dict_york.values())
- Let's set the province value to BC:
dict_york['Province'] = 'BC' print(dict_york) print(dict_york.keys()) print(dict_york.values())
- For example:
dict_york['Province'] = 'ON' print(dict_york) print(dict_york.keys()) print(dict_york.values())
You should notice that value for the 'Province' key has been changed back to 'ON'.
The lists that contain the values and keys of the dictionary are not real python lists - they are "views of the dictionary" and therefore are immutable.
- You could change these views into usable lists by using the list() function:
list_of_keys = list(dict_york.keys()) print(list_of_keys[0])
- Lists can be used with for loops:
list_of_keys = list(dict_york.keys()) for key in list_of_keys: print(key) for value in dict_york.values(): print(value)
Practice working with dictionaries
- Create the ~/ops435/lab4/lab4c.py program. The purpose of this program will be to create dictionaries, extract data from dictionaries, and to make comparisons between dictionaries.
- Use the following as a template:
#!/usr/bin/env python3 # Dictionaries dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Province': 'ON'} dict_newnham = {'Address': '1750 Finch Ave E', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M2J2X5', 'Province': 'ON'} # Lists list_keys = ['Address', 'City', 'Country', 'Postal Code', 'Province'] list_values = ['70 The Pond Rd', 'Toronto', 'Canada', 'M3J3M6', 'ON'] def create_dictionary(keys, values): # Place code here - refer to function specifics in section below def shared_values(dict1, dict2): # Place code here - refer to function specifics in section below if __name__ == '__main__': york = create_dictionary(list_keys, list_values) print('York: ', york) common = shared_values(dict_york, dict_newnham) print('Shared Values', common)
- Your create_dictionary() function should:
- accept two lists as arguments keys and values, combining these lists together to create a dictionary
(Tip: use a while loop to access elements in both the keys and values lists at the same time). - return a dictionary that has the keys and associated values from the lists.
- Your shared_values() function should:
- accept two dictionaries as arguments and find all values that are shared between the two dictionaries
(Tip: generate sets containing only values for each dictionary, then use a function mentioned in a previous section to store the values that are common to both lists) - return a set containing ONLY values found in BOTH dictionaries
Sample Run 1:
./lab4c.py
York: {'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Address': '70 The Pond Rd', 'Province': 'ON', 'City': 'Toronto'}
Shared Values {'Canada', 'ON', 'Toronto'}
Sample Run 2 (with import):
import lab4c
dict_york = {'Address': '70 The Pond Rd', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M3J3M6', 'Province': 'ON'}
dict_newnham = {'Address': '1750 Finch Ave E', 'City': 'Toronto', 'Country': 'Canada', 'Postal Code': 'M2J2X5', 'Province': 'ON'}
list_keys = ['Address', 'City', 'Country', 'Postal Code', 'Province']
list_values = ['70 The Pond Rd', 'Toronto', 'Canada', 'M3J3M6', 'ON']
york = lab4c.create_dictionary(list_keys, list_values)
print(york)
# Will print: {'Address': '70 The Pond Rd',
'City': 'Toronto',
'Country': 'Canada',
'Postal Code': 'M3J3M6',
'Province': 'ON'}
common = lab4c.shared_values(dict_york, dict_newnham)
print(common)
# Will print: {'Canada', 'ON', 'Toronto'}
- Download the checking script and check your work. Enter the following commands from the bash shell.
cd ~/ops435/lab4/ pwd #confirm that you are in the right directory ls CheckLab4.py || wget http://ops345.ca/ops445/CheckLab4.py python3 ./CheckLab4.py -f -v lab4c
- Before proceeding, make certain that you identify all errors in lab4c.py. When the checking script tells you everything is OK proceed to the next step.
LAB 4 SIGN-OFF (SHOW INSTRUCTOR)
- Have Ready to Show Your Instructor:
- ✓ Output of:
./CheckLab4.py -f -v
- ✓ Output of:
cat lab4a.py lab4b.py lab4c.py lab4d.py
- ✓ Output of:
LAB REVIEW
- What is the purpose of a tuple? How does a tuple differ from a list?
- How do you define elements within a tuple?
- Write Python code to confirm if the string 'OPS435' exists within the tuple called courses.
- What is the purpose of a set? How do sets differ from lists or tuples?
- How do you define elements within a set?
- Assuming you have defined two sets called set1 and set2. Write Python code to:
- Return a set containing all values of both sets
- Returns a set containing all values in set1 that are not found in set2
- Return a set containing all values that both sets DO NOT share
- What is the purpose of a dictionary?
- How do you define elements within a dictionary?
- Write Python commands to display for a dictionary called my_dictionary the dictionary key called my_key and a dictionary value for that key?
- What is the purpose for the range(), len(), append(), and map() functions for a dictionary?
- List and briefly explain the following functions (methods) that can be used with strings:
lower() , upper() , swapcase() , title() , captilize() , split() - Assume you issued the following command in your ipython3 shell:
course_name = 'Programming with Python'
What will be the output for each of the following Python commands?- course_name[3:11]
- course_name[10:]
- course_name[-1]