CPSC 103
Final Exam
2. [4 Marks] For each of the following code snippets for Jupyter cells, fill in the box with the value that Jupyter would show when the cell is run; that is, the value of the last expression. In case if the code throws any kind of error, write Error in the box.
a. def squared(x):
return x * x
x = 2
y = squared(x)
squared(y)
x = squared(y)
x
b. code = 'cpsc103'
sub = code[:len(code) – 1]
sub
c.
values = ['cpsc', '103', '911']
str_list = '' # type: List[str]
for s in values:
str_list = str_list + s
str_list
d. x = 1
p = 2 * 100 + 10 / 5
return x
p = p * x
p
3. [20 Marks] You are working as a software engineer in a big company that builds and maintains LMS systems such as Canvas used by universities. Following are the data definitions designed to represent a user of the LMS website and different roles assigned to them. The data definitions were designed using the knowledge gained from CPSC 103, however, there are many syntactical as well as design issues (i.e., not following the design recipes). Each line of code below has a line number at the front. Identify the line of code which has issue(s) and write its line number and the correct and complete line of code on page 6. If the line of code needs to be removed, then write Remove in corrected code column on page 6. In total, there are 10 lines which have issues. Please note there is no indentation error/issue.
1. Role = Enum('Role', ['Student', 'Instructor', 'TA', 'Coordinator'])
2. # interp. A role assigned to a user on Canvas, one of
3. # ‘Student','Instructor', 'TA', or 'Coordinator'.
4.
5. R0 = Role('Student')
6.
7. # Template based on Enumeration (5 cases)
8. @typecheck
9. def fn_for_role(r:Role) -> ...:
10. if r == Role.Student:
11. return ...
12. elif r == Role.Instructor:
13. return ...
14. elif r == Role.TA:
15. return ...
16. elif r == Role.Coordinator:
17. return ...
18. else:
19. return ...
20. # Optional[str]
21. # interp. An optional string value.
22.
23. S0 = None
24. S1 = 'Final Exam'
25.
26. # Template based on Optional
27. @typecheck
28. def fn_for_os(os: Optional[str]) -> ...:
29. if os is None:
30. return ...
31. else:
32. return ...(os)
33. # List[Role]
34. # interp. A list of roles assigned to a user.
35.
36. L0 = []
37. L1 = ['Student', 'TA']
38.
39. # Template based on Arbitrary-sized
40. @typecheck
41. def fn_for_lor(lor: List[Role]) -> ...:
42. # description of the accumulator
43. acc = ... # type: Role
44. for r in lor:
45. acc = ...(fn_for_role(r), acc)
46. return ...(acc)
47. User = NamedTuple('User', [('name', str),
48. ('role', List[Role]),
49. ('email', Optional[str]),
50. ('password', str),
51. ('uid', int) # in range [3999, 6999]
52. ])
53. # interp. A user of Canvas website represented with a name, assigned
54. roles, optional email, password and a unique ID from 3999 - 6999.
55.
56. U1 = User('George', [], '[email protected]', 'XYZ', 4190)
57. U2 = User('Wash', ['Student'], '[email protected]', 'PQRX', 6999)
58. U3 = User('Jess', Role.Instructor, '[email protected]', '123', 5902)
59. U4 = User('Ash', [Role.TA], 'None', '1989', 4403)
60.
61.
62. # Template based on Compound (5 fields) and reference rule
63. @typecheck
64. def fn_for_user(u: User) -> ...:
65. return ...(u.name,
66. fn_for_role(u.role),
67. u.email,
68. u.password,
69. u.uid)
4. [10 Marks] You are trying to analyze the sentiments of a tweet on a social media platform. A tweet is a short text message posted on a social media website called Twitter. A sentiment of a tweet can either be POSITIVE, NEGATIVE or NEUTRAL. The sentiment of a tweet can be identified by comparing the number of positive words and negative words in a tweet. A tweet can neither have positive nor negative words as well.
a. If a tweet has more positive words than negative words, then sentiment is POSITIVE.
b. If a tweet has more negative words than positive words, then sentiment is NEGATIVE.
c. In all other cases, sentiment is NEUTRAL.
Design a function that takes a tweet and returns the correct sentiment for it. Use the following data definitions in your function design. Follow all the steps of HtDF recipe.
Following data definitions represent a tweet by number of positive and negative words it contains, and sentiments as an Enumeration.
Tweet = NamedTuple('Tweet', [('id', str),
('pos_words', int), # in range [0, ...)
('neg_words', int) # in range [0, ...)
])
# interp. Represents a tweet posted on a social media platform. consists of an id, number of positive words ('pos_words') and the number of negative words ('neg_words') it contains.
T1 = Tweet('ABC', 0, 4)
T2 = Tweet('PQR', 6, 0)
# Template based on Compound
@typecheck
def fn_for_tweet(t: tweet) -> ...:
return ...(t.id,
t.pos_words,
t.neg_words)
Sentiment = Enum('Sentiment', ['NEGATIVE', 'NEUTRAL', 'POSITIVE'])
# interp. Represents the Sentiment assigned to a tweet, is one of
# NEGATIVE, NEUTRAL, or POSITIVE.
# Examples are redundant for Enumerations
# Template based on Enumeration
@typecheck
def fn_for_sentiment(s: Sentiment) -> ...:
if s == Sentiment.NEGATIVE:
return ...
elif s == Sentiment.NEUTRAL:
return ...
elif s == Sentiment.POSITIVE:
return ...
5. [7 Marks] Design a data definition to represent the Internet download speed. The speed may be unknown, but when it is known, it is measured in Mbps.
6. [15 marks] You want to visualize the calories you burnt during the workout each day in the last week. Design a function that takes a list of workouts (as defined below) and produces a line chart showing how many calories you burnt each day after the workout. You can assume that the input list is sorted in the ⼀ order of days from 1 – 7. Design all the helper functions needed to complete the task using complete HtDF recipe. Make sure to add axis labels and chart title.
from typing import NamedTuple
Workout = NamedTuple('Workout', [('day', int), # in range [1, 7]
('calories', int) # in range [0, ...)
])
# interp. A record of calories burnt each day during the workout session.
W1 = Workout(1, 250)
W2 = Workout(2, 300)
# Template based on Compound
@typecheck
def fn_for_workout(w: Workout) -> ...:
return ...(w.day,
w.calories)
# List[Workout]
# interp. A list of workouts.
LOW0 = []
LOW1 = [W1, W2]
# Template based on Arbitrary-sized and reference rule
@typecheck
def fn_for_low(low: List[Workout]) -> ...:
# description of the accumulator
acc = ... # type: ...
for w in low:
acc = ...(acc, fn_for_workout(w))
return ...(acc)
# List[int]
# interp. A list of integers.
LOI0 = []
LOI1 = [1,2, 3, 4]
# Template based on Arbitrary-sized
@typecheck
def fn_for_loi(loi: List[int]) -> ... :
#description of the accumulator
acc = ... #type: ...
for i in loi:
acc = ...(acc, i)
return ...(acc)
from matplotlib import pyplot as pyplot
7. [7 Marks] Imagine, you own a channel on a video streaming website such as YouTube. Following is a daily statistics report of videos being watched on your channel which you want to read into a program for analysis.
ID Video Title Genre Length (in mins) Daily Views Watch time (in mins) Ads
T39gyk= Python for Beginners Education 10 50 350 Yes
Af35lp Prepare Pasta in 20 mins Food 8 25 200 Yes
98gdfk Guitar Composition Music 10 20 180 No
12jsh0= Differential Equations 101 Education 20 30 589 No
1jso8h Easy to make Smoothies Food 10 130 790 Yes
Here are the data definitions that can be used to represent the relevant parts of this information as data in your program. THE PROBLEM STATEMENT IS ON THE NEXT PAGE.
from typing import NamedTuple, List
from enum import Enum
import csv
Genre = Enum('Genre', ['Education', 'Food', 'Music'])
# interp. Represents the genre of videos you have on your channel,
# one of 'Education', 'Food', or 'Music'.
# Examples are redundant for enumerations
# Template based on Enumeration (3 cases)
def fn_for_genre(g: Genre) -> ...:
if g == Genre.Education:
return ...
elif g == Genre.Food:
return ...
elif g == Genre.Music:
return ...
# List[Genre]
# interp. A List of video genres.
LOG0 = []
LOG1 = [Genre.Education, Genre.Music, Genre.Food]
# Template based on Arbitrary-list
@typecheck
def fn_for_log(log:List[Genre]) -> ...:
#description of the accumulator
acc = ... # type: ...
for g in log:
acc = ...(acc, fn_for_genre(g))
Return ...(acc)
VideoData = NamedTuple('VideoData', [('genre', Genre),
('views', int), # in range [0, ...)
('ads', bool)])
# interp. Represents a viewing statistic of a video consists of genre, number of views and whether the video played an ad or not.
VD1 = VideoData(Genre.Education, 50, True)
VD2 = VideoData(Genre.Food, 25, True)
VD3 = VideoData(Genre.Music, 20, False)
VD4 = VideoData(Genre.Education, 30, False)
VD5 = VideoData(Genre.Food, 130, True)
# Template based on Compound and reference rule
@typecheck
def fn_for_video_data(vd: Video) -> ...:
return ...(fn_for_genre(vd.genre),
vd.views,
vd.ads)
# List[VideoData]
#interp. a list of video data statistics
LOVD0 = []
LOVD1 = [VD1, VD2, VD3, VD4, VD5]
# Template based on Arbitrary-sized and reference rule
@typecheck
def fn_for_lovd(lovd: List[VideoData]) -> ...:
# description of the accumulator
acc = ... # type: ...
for vd in lovd:
acc = ...(acc, fn_for_video_data(vd))
return ...(acc)
Continuing Problem 7: Complete the read function (given on the next page) to read this information from a file and store it as data in your program. You can use the helper functions given below as needed. You can safely assume that given helper function is complete and correct. You cannot make any other assumptions about the file you are given. You do not need to add tests for the read function.
def parse_genre(gen: str) -> Genre:
'''
parses the given string gen into one of the Genre.
'''
# return Genre.Education # stub
def parse_ads(bool_str: str) -> bool:
'''
returns True if the bool_str is ‘YES’, False if it is ‘NO’.
'''
return True # stub
@typecheck
def read(filename: str) -> __________________________________:
‘’’
Reads the specified file and returns _____________________________________
‘’’
# return [] # stub
# Template from HtDAP
8. [9 Marks] You want to know what the average number of views for each genre on your channel is.
Complete the design of two functions avg_views_by_genres and avg_by_one_genre. You must use all the helper functions given at least once between the following two functions (You don’t need to create tests for any function in this question). Note: This question uses the data definitions defined in Q7.
@typecheck
def avg_views_by_genres(log: List[Genre], lovd: List[VideoData]) -> List[float]:
'''
Calculates the average number of views on the videos for each genre in log found in the list lovd. The list lovd can never be empty.
'''
# return [] # stub
# Template copied from List[Genre] with one additional parameter
@typecheck
def avg_by_one_genre(lovd: List[VideoData], g: Genre) -> float:
'''
Calculates the average views to the videos in lovd for a given genre g.
Returns 0 if the list is empty.
'''
# return 0 # stub
# Template based on Composition
def filter_by_genre(lovd: List[VideoData], g: Genre) -> List[VideoData]:
'''
Returns a list of video data from lovd that belongs to the given genre g.
'''
return [] # stub
def sum_views(lovd: List[VideoData]) -> int:
'''
Returns the sum of views of all the video data in lovd.
Returns 0 if the list is empty.
'''
return 0 # stub
def count_videos(lovd: List[VideoData]) -> int:
'''
Returns the sum of views of all the video data in lovd.
Returns 0 if the list is empty.
'''
return 0 # stub
9. [18 Marks] Finally, complete the design of filter_by_genre function and write all the helper functions as needed using HtDF recipe. You need to write at least 1 test for each function.
Note: This question uses the data definitions defined in Q7.
def filter_by_genre(lovd: List[VideoData], g: Genre) -> List[VideoData]:
'''
Returns a list of video data from lovd that belongs to the given genre g.
Returns an empty list if lovd is empty or no video found for given g.
'''
return [] # stub