Problem Set 2: Program flow, functions, and decisions
Preliminaries
In your work on this assignment, make sure to abide by the collaboration policies of the course.
For each problem in this problem set, we will be writing or evaluating some Python code. You are encouraged to use the Spyder IDE which will be discussed/presented in class, but you are welcome to use another IDE if you choose.
If you have questions while working on this assignment, please post them on Piazza! This is the best way to get a quick response from your classmates and the course staff.
Programming Guidelines
-
Refer to the class Coding Standards for important style guidelines. The grader will be awarding/deducting points for writing code that comforms to these standards.
-
Every program file must begin with a descriptive header comment that includes your name, username/BU email, and a brief description of the work contained in the file.
-
Every function must include a descriptive docstring that explains what the function does and identifies/defines each of the parameters to the function.
-
Your functions must have the exact names specified below, or we won’t be able to test them. Note in particular that the case of the letters matters (all of them should be lowercase), and that some of the names include an underscore character (
_
). -
Make sure that your functions return the specified value, rather than printing it. None of these functions should use a
print
statement. -
If a function takes more than one input, you must keep the inputs in the order that we have specified.
-
You should not use any Python features that we have not discussed in class or read about in the textbook.
-
Your functions do not need to handle bad inputs – inputs with a type or value that doesn’t correspond to the description of the inputs provided in the problem.
-
You must test your work before you submit it You can prove to yourself whether it works correctly – or not – and make corrections before submission. If you need help testing your code, please ask the course staff!
-
Do not submit work with syntax errors. Syntax errors will cause the Gradescope autograder to fail, resulting in a grade of 0.
Warnings: Individual Work and Academic Conduct!!
-
This is an individual assignment. You may discuss the problem statement/requirements, Python syntax, test cases, and error messages with your classmates. However, each student must write their own code without copying or referring to other student’s work.
-
It is strictly forbidden to use any code that you find from online websites including but not limited to as CourseHero, Chegg, or any other sites that publish homework solutions.
-
It is strictly forbidden to use any generative AI (e.g., ChatGPT or any similar tools**) to write solutions for for any assignment.
Students who submit work that is not authentically their own individual work will earn a grade of 0 on this assignment and a reprimand from the office of the Dean.
If you have questions while working on this assignment, please post them on Piazza! This is the best way to get a quick response from your classmates and the course staff.
Problem 1: Program flow and variable scope
10 points
Try to do this part before workshop time!
Begin by downloading this text file: ps2pr1.txt
.
Rick-click on the link, and use “Save As...” to save the text file to your computer.
Edit this file, and save your work in this part into that file.
-
Consider the following Python program:
x = 11 y = 5 x = x + 6 z = y + x x = x // 7 y = z % 3
Copy the table shown below into your text file for this problem, and fill in the missing rows/values to illustrate how the values of the variables change over the course of the program. We’ve given you the values of the variables after the first two lines of code. You should complete the remaining rows of the table.
line of code | x | y | z | -------------------------------- x = 11 | 11 | | | y = 5 | 11 | 5 | | x = x + 6 | | | | z = y + x | | | | x = x // 7 | | | | y = z % 3 | | | |
-
Consider the following Python program:
def foo(a, b): b = b - 2 a = a - b print('foo', a, b) return a a = 5 b = 3 print(a, b) a = foo(a, b) print(a, b) foo(b, a) print(a, b)
In section 2-2 of
ps2pr1.txt
, we have given you tables like the ones shown below:global variables (ones that belong to the global scope) a | b ----------- 5 | 3 | local variables (ones that belong to foo) a | b ----------- | | output (the lines printed by the program) ------ 5 3
We have started the first and third tables for you. You should:
- complete the first and second tables so that they illustrate how the values of the variables change over time
- complete the third table so that it shows the output of the program (i.e., the values that are printed).
You may not need all of the rows provided in the tables.
-
Consider the following Python program:
def wow(a): b = a * 2 print('wow:', a, b) return b def yay(b): a = wow(b) + wow(b + 2) print('yay:', a, b) return a a = 4 b = 3 print(a, b) b = wow(b) print(a, b) yay(a) print(a, b)
In section 2-3 of
ps2pr1.txt
, we have given you tables like the ones shown below:global variables (ones that belong to the global scope) a | b ----------- 4 | 3 | wow's local variables a | b ----------- | | yay's local variables a | b ----------- | | output (the lines printed by the program) ------ 4 3
We have started the first and fourth tables for you. You should:
- complete the first three tables so that they illustrate how the values of the variables change over time
- complete the last table so that it shows the output of the program (i.e., the values that are printed).
You may not need all of the rows provided in the tables.
Problem 2: Functions on strings and lists
30 points
Begin this part before workshop time!
In Spyder, use the File -> New File menu option to open a new editor
tab for your program, and save it using the the name ps2pr2.py
.
Make sure to specify the .py
extension.
Include comments at the top of the file that are similar to the ones
that we gave you at the top of ps1pr3.py
.
-
Write a function
first_and_last(values)
that takes a listvalues
and returns a new list containing the first value of the original list followed by the last value of the original list. You may assume that the original list has at least one value.Although this function could be completed in one line, you must use the following template:
def first_and_last(values): """ put your docstring here """ first = ________ last = ________ return [first, last]
Here are some examples of how the function should work:
>>> first_and_last([1, 2, 3, 4]) [1, 4] >>> first_and_last([7]) # 7 is both first and last! [7, 7] >>> first_and_last(['how', 'are', 'you?']) ['how', 'you?']
Warning
Remember that your functions should return the correct value rather than printing it. If your function is printing the return value, you will see the word
None
as part of the output for the last test above. If you are seeingNone
in your output, you must fix your function so that it uses areturn
statement rather than aprint
statement. This same warning applies to all of the functions that you will write for this assignment, with the exception of the optional test functions that you may include for testing your code. -
Write a function
move_to_end(s, n)
that takes as inputs a string values
and an integern
, and that returns the a new string in which the firstn
characters ofs
have been moved to the end of the string. For example:>>> move_to_end('computer', 3) # move 'com' after 'puter' 'putercom' >>> move_to_end('computer', 5) # move 'compu' after 'ter' 'tercompu' >>> move_to_end('computer', 0) computer
Special case: If
n
(the second input) is greater than or equal to the length ofs
(the first input), then the function should simply return the originals
without changing it:>>> move_to_end('hi', 5) # 5 > len('hi') 'hi'
-
Write a function
truncate(s, max_length)
that takes a string parameters
and an integer parametermax_length
, and returns the firstmax_length
characters ofs
. Use the slicing operatorHere are some examples:
>>> truncate('the long and winding road', 12) 'the long and' >>> truncate('get back', 12) # fewer than 12 characters in s; 'get back'
Note that when
s
is shorter thanmax_length
, the entire strings
is returned. -
Write a function
triple_outsides(s)
that takes a strings
, and returns a version of that string with the first and last characters repeated 3 times, and the rest of the characters in the middle occuring only once each.>>> triple_outsides('cayenne') 'cccayenneee' >>> triple_outsides('') ''
-
Write a function
every_other(s)
that takes a strings
and returns a version of that string with every other character has been skipped.>>> every_other('abcde') 'ace' >>> every_other('across the universe') 'ars h nvre'
Hints: * use indexing when you need an individual character * use the slicing operator to break the string into parts * use separate variables for each part
-
Write a function
rotate(s, n)
that takes a strings
and an integern
, and returns a new string in which each character has been movedn
positions to the left. Characters that “fall off” the beginning of the left should be concatenated to the right (end) of the resulting string.>>> rotate('abcdef', 1) 'bcdefa' >>> rotate('obladi, oblada', 2) 'ladi, obladaob'
Hint: * use the slicing operator to break the string into parts * use separate variables for each part
-
Write a function
mirror(s)
that takes as input a strings
and returns a mirrored version ofs
that is twice the length of the original string. For example:>>> mirror('bacon') 'baconnocab' >>> print(mirror('XYZ')) XYZZYX
Hint: Use skip-slicing!
-
Write a function
replace_end(values, new_end_vals)
that takes as inputs a listvalues
and another listnew_end_vals
, and that returns a new list in which the elements innew_end_vals
have replaced the lastn
elements of the listvalues
, wheren
is the length ofnew_end_vals
. For example:>>> replace_end([1, 2, 3, 4, 5], [7, 8, 9]) [1, 2, 7, 8, 9]
In the above example, the second input has a length of 3, so we replace the last 3 elements of the first input (the elements
[3, 4, 5]
) with the elements specified by the second input ([7, 8, 9]
).Other examples:
>>> replace_end([1, 2, 3, 4, 5], [10, 11]) [1, 2, 3, 10, 11] >>> print(replace_end([1, 2, 3, 4, 5], [12])) [1, 2, 3, 4, 12]
Special case: If the length of the second input is greater than or equal to the length of the first input, then the function should simply return the original second input:
>>> replace_end([0, 2, 4, 6], [4, 3, 2, 1]) [4, 3, 2, 1] >>> replace_end([0, 2, 4, 6], [4, 3, 2, 1, 0]) [4, 3, 2, 1, 0]
Hint: Begin by computing the length of
new_end_vals
and storing it in an appropriately named variable. Then use that variable in the rest of your code. -
Write a function
repeat_elem(values, index, num_times)
that takes as inputs a listvalues
, an integerindex
(which you may assume is a valid index for one of the elements invalues
), and a positive integernum_times
, and that returns a new list in which the element ofvalues
at positionindex
has been repeatednum_times
times. For example:>>> repeat_elem([10, 11, 12, 13], 2, 4) [10, 11, 12, 12, 12, 12, 13]
In the above example, the second input is
2
and the third input is4
, so we take the element at position 2 of the list (the12
) and repeat it4
times.Other examples:
>>> repeat_elem([10, 11, 12, 13], 2, 6) # repeat element 2 six times [10, 11, 12, 12, 12, 12, 12, 12, 13] >>> print(repeat_elem([5, 6, 7], 1, 3)) # repeat element 1 three times [5, 6, 6, 6, 7]
Don’t forget to test your functions. You may also find it helpful to use the Python Tutor visualizer to trace through the execution of your functions.
Problem 3: Functions with Decision Statements
20 points
In Spyder, use the File -> New File menu option to open a new editor
tab for your program, and save it using the the name ps2pr3.py
.
Make sure to specify the .py
extension.
Include comments at the top of the file that are similar to the ones
that we gave you at the top of ps1pr4.py
.
In this problem, you will write functions that use decision statements in producing their result.
-
Write a function
my_min(a,b)
that takes 2 parameters and returns the minimum of these two. Inside your function, use decision logic to identify and return the minimum value among the parameters. Test your function using these statements at the bottom of your file. For example:>>> my_min(1,2) 1 >>> my_min(2,1) 1
Your function must use conditional execution, and it should not use Python’s built-in
min
function. You may use other built-in functions as needed. -
Write a function
find_min(a, b, c)
that takes 3 parameters and returns the minimum of these three. Inside your function, use decision logic to identify and return the minimum value among the parameters.>>> find_min(1,2,3) 1 >>> find_min(3,1,2) 1 >>> find_min(-3,-1,-2) -3
Write test cases at the bottom of your file to test all possible permutations of the parameters, e.g., minimum in the first parameter (1,2,3), minimum in the middle parameter (2,1,3), minimum in the third parameter (3,2,1), as well as multiple parameters with the same minimum (e.g., 1, 1, 2), etc.
You will need eight test cases to ensure it works correctly.
Your function must use conditional execution, and it should not use Python’s built-in
min
function. You may use other built-in functions as needed. -
Write a function
longer_len(s1, s2)
that takes as inputs two string valuess1
ands2
, and that returns the length of the longer string. For example:>>> longer_len('computer', 'compute') 8 >>> longer_len('hi', 'hello') 5 >>> print(longer_len('begin', 'on')) 5
Your function must use conditional execution, and it should not use Python’s built-in
max
function. You may use other built-in functions as needed. -
Write a function
is_mirror(s)
that takes as input a strings
and returnsTrue
ifs
is a mirrored string (i.e., a string that could have been produced by yourmirror
function) andFalse
otherwise. Examples:>>> is_mirror('baconnocab') True >>> print(is_mirror('baconnoca')) False
Warning
Your function should return a boolean value – either
True
orFalse
, without any quotes around them. If you see quotes around the result when you make the first call above from the Shell, you must fix your function to remove the quotes.Hints:
- You may find it helpful to compute the value
len(s) // 2
as part of this function. - You may also find it helpful to call your previous
mirror
function, although doing so is not required.
- You may find it helpful to compute the value
Problem 4: Validating Data
30 points
In Spyder, use the File -> New File menu option to open a new editor
tab for your program, and save it using the the name ps2pr4.py
.
Make sure to specify the .py
extension.
Include comments at the top of the file that are similar to the ones
that we gave you at the top of ps1pr4.py
.
In this part of the assignment, you will use decision statements to validate some parameter data, to determine whether the parameters can be interpreted as a valid calendar date.
For example:
5/24/2008 is a valid date 9/31/2018 is not a valid date, because day 31 is not valid date for September 2018. 2/29/2000 is a valid date 2/29/2100 is not valid, because day 29 is not valid date for February 2100.
Decomposing the Problem
You will write several helper functions to decompose this problem, and then use these helper functions to implement the complete solution. It is strongly recommended that you write each function in the order presented here, and test each one thoroughly before moving on to the next function.
The first 4 functions will NOT produce any output (print) statements, but rather only
produce a result (return value). You may use print
statements in these functions
while writing/debugging them, but comment out the print statements from your
final work.
Important Notes
-
Do not take user input from the keyboard (i.e., the
input
function) in any of your code for this assignment. -
Hint: in each function, deal with the “invalid” cases first, and return
False
; a return statement always stops the function.
At the end of the function, if nothing is invalid, you will returnTrue
.
-
Write a function
is_valid_month(month)
, wheremonth
is an integer parameter. The function returnsTrue
if the month is valid, and False otherwise. You will need at least three test cases to ensure it works correctly. For example:- Month 5 is valid.
- Month -5 is not a valid month.
- Month 15 is not a valid month.
-
Write a function
is_leap_year(year)
, whereyear
is an integer parameter. The function returnsTrue
if the year is a leap year, and False otherwise.You may be familiar with the idea that every fourth year is a leap year (e.g., 2020, 2024, 2028, ...).
In fact, the algorithm for selecting leap years is a bit more subtle. Here is a great explanation by Neil DeGrasse Tyson:
Briefly:
- Any year divisible by 400 is a leap year. (e.g., 2000, 2400)
- Other centuries are not leap years (e.g., 2100 is not a leap year)
- Other years divisible by 4 are leap years (e.g., 2020, 2024)
- All other years are not leap years.
You will need at least four test cases to ensure it works correctly.
-
Write a function
is_valid_day_in_month(month, day, year)
, wheremonth
,day
, andyear
are integer parameters. The function returnsTrue
if the day number is valid within the month, andFalse
otherwise. The rules are:- January, March, May, July, August, October and December have 31 days.
- April, June, September, and November have only 30 days.
- February has 28 days except in leap years when it has 29 days (hence the inclusion of the parameter year)
For example:
- Day 5 is valid in any month.
- Day -5 is not valid in any month.
- Day 35 is not valid in any month.
- Day 31 is valid in some months but not others
- Day 29 is valid in February only if it is a leap year
You will need at least six test cases to ensure it works correctly.
-
Write the function
get_month_name(month)
. This function takes an integer parametermonth
and must return the name of the month as astring
.For example,
get_month_name(9)
will return'September'
. -
Write the function
is_valid_date(month, day, year)
that takes integer parameters for themonth
,day
, andyear
, and then returnsTrue
if this is a valid date andFalse
if it is not a valid date.In this function, you will re-use the work from your previous (helper) functions. That is, you will call the helper functions, and test the results (using
if/else
statements).If the date is not valid, print an output message explaining why it is not valid.
Finally, the function must return the result of
True
orFalse
.
Testing Your Work
Here is some sample output that was generated by some of our test cases.
Note that you will need to write the code to call your is_valid_date
function –
what is printed below is only the output and a print
out of the return value
(True
or False
).
This is not an exhaustive list of test cases. Moreover, the autograder script will test only some of your cases before the deadline (to ensure that your) functions are callable and return the correct type of data. They will not test your logic thoroughly until after the due date.
02/29/2016 is a valid date. True 02/29/2017 is a not valid date, because day 29 is not valid date for February 2017 False 02/29/2018 is a not valid date, because day 29 is not valid date for February 2018 False 01/32/2018 is a not valid date, because day 32 is not valid date for January 2018 False 13/07/2018 is a not valid date, because 13 is not a valid month. False
Important Notes
-
You do not need to match this output exactly. You do need to correctly return
True
orFalse
. -
Do not take user input from the keyboard (i.e., the
input
function) in any of your code for this problem.
Submitting Your Work
You should use Gradesope to submit the following files:
- your modified
ps2pr1.txt
file containing your solutions for Problem 1 - your
ps2pr2.py
file containing your solutions for Problem 2 - your
ps2pr3.py
file containing your solutions for Problem 3 - your
ps2pr4.py
file containing your solutions for Problem 4
Warnings
-
Make sure to use these exact file names, or Gradescope will not accept your files. If Gradescope reports that a file does not have the correct name, you should rename the file using the name listed in the assignment page.
-
If you make any last-minute changes to one of your Python files (e.g., adding additional comments), you should run the file in Spyder after you make the changes to ensure that it still runs correctly. Even seemingly minor changes can cause your code to become unrunnable.
-
If you submit an unrunnable file, Gradescope will accept your file, but it will not be able to auto-grade it. If time permits, you are strongly encouraged to fix your file and resubmit. Otherwise, your code will fail most if not all of our tests.
Important note regarding test cases and Gradescope:
- You must test each function after you write it. Here are two ways to do so:
- Run your file after you finish a given function. Doing so will bring you to the Shell, where you can call the function using different inputs and check to see that you obtain the correct outputs.
Warning: Beware of Global print
statements
- The autograder script cannot handle
print
statements in the global scope, and their inclusion causes this error:
* Why does this happen? When the autograder imports your file, the `print` statement(s) execute (at import time), which causes this error. * You can prevent this error by not having any `print` statements in the global scope. Instead, create an `if __name__ == '__main__':` section at the bottom of the file, and put any test cases/print statements in that controlled block. For example: if __name__ == '__main__': ## put test cases here: print('future_value(0.05, 2, 100)', future_value(0.05, 2, 100)) * `print` statements inside of functions do not cause this problem.