""" PRACTICE Exam 3. This problem provides practice at: *** LOOPS WITHIN LOOPS in SEQUENCE of SEQUENCES problems. *** Authors: David Mutchler, Vibha Alangar, Dave Fisher, Matt Boutell, Mark Hays, Mohammed Noureddine, Sana Ebrahimi, Sriram Mohan, their colleagues and PUT_YOUR_NAME_HERE. """ # TODO: 1. PUT YOUR NAME IN THE ABOVE LINE. ############################################################################### # TODO: 2. [Note: same _TODO_ as its matching one in module m1.] # Students: # __ # These problems have DIFFICULTY and TIME ratings: # DIFFICULTY rating: 1 to 10, where: # 1 is very easy # 3 is an "easy" Exam 3 question. # 5 is a "typical" Exam 3 question. # 7 is a "hard" Exam 3 question. # 10 is an EXTREMELY hard problem (too hard for a Exam 3 question) # __ # TIME ratings: A ROUGH estimate of the number of minutes that we # would expect a well-prepared student to take on the problem. # __ # IMPORTANT: For ALL the problems in this module, # if you reach the time estimate and are NOT close to a solution, # STOP working on that problem and ASK YOUR INSTRUCTOR FOR HELP on it, # in class or via Piazza. # __ # After you read (and understand) the above, change this _TODO_ to DONE. ############################################################################### import time import testing_helper def main(): """ Calls the TEST functions in this module. """ print() print("Un-comment and re-comment calls in MAIN one by one as you work.") run_test_smallest_increase() run_test_two_d_smallest_increase() run_test_sum_bigger_than_average() def run_test_smallest_increase(): """ Tests the smallest_increase function. """ print() print('--------------------------------------------------') print('Testing the smallest_increase function:') print('--------------------------------------------------') format_string = ' smallest_increase( {} )' test_results = [0, 0] # Number of tests passed, failed. # Test 1: numbers = [10, 15, 3, 20, 22, 28, 20, 11] expected = -12 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 2: numbers = [-4, -10, 20, 5] expected = -15 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 3: numbers = [2, 5, 10, 11, 35] expected = 1 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 4: Same as Test 1, but a tuple (which will reveal mutating in error) numbers = (10, 15, 3, 20, 22, 28, 20, 11) expected = -12 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 5: numbers = (30, 20, 25, 18, 20, 18, 30, 25) expected = -10 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 6: numbers = (25, 30, 20, 25, 18, 20, 18, 30, 25) expected = -10 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 7: numbers = (25, 18, 30, 20, 18, 20, 18, 30, 25) expected = -10 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 8: numbers = (25, 18, 20, 18, 25, 30, 20, 30, 25) expected = -10 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 9: numbers = (25, 18, 20, 18, 30, 30, 20, 25) expected = -10 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 10: numbers = (25, 18, 20, 18, 30, 25, 30, 20) expected = -10 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 11: numbers = (25, 20) expected = -5 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 12: numbers = (20, 25) expected = 5 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 13: numbers = (30, 30) expected = 0 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = smallest_increase(numbers) print_actual_result_of_test(expected, actual, test_results) # SUMMARY of test results: print_summary_of_test_results(test_results) def smallest_increase(numbers): """ What comes in: A sequence of numbers whose length is at least 2. What goes out: The smallest "increase" from one number in the sequence to the next number in the sequence, where the INCREASE from A to B is (by definition) B - A. Note that the "increase" can be negative; for example, the "increase" from 10 to 2 is -8. See examples. Side effects: None. Examples: smallest_increase( [10, 15, 3, 20, 22, 28, 20, 11] ) examines the increases: from 10 to 15 (increase is 15 - 10, which is 5) from 15 to 3 (increase is 3 - 15, which is -12) from 3 to 20 (increase is 20 - 3, which is 17) from 20 to 22 (increase is 22 - 20, which is 2) from 22 to 28 (increase is 28 - 22, which is 6) from 28 to 20 (increase is 20 - 28, which is -8) from 20 to 11 (increase is 11 - 20, which is -9) and the smallest of those increases is -12, so the function returns -12 in this example. smallest_increase( [-4, -10, 20, 5] ) examines the increases: from -4 to -10 (increase is -10 - (-4)), which is -6) from -10 to 20 (increase is 20 - (-10), which is 30) from 20 to 5 (increase is 5 - 20, which is -15) and the smallest of those increases is -15, so the function returns -15 in this example. smallest_increase( [2, 5, 10, 11, 35] ) examines the increases: from 2 to 5 (increase is 5 - 2, which is 3) from 5 to 10 (increase is 10 - 5, which is 5) from 10 to 11 (increase is 11 - 10, which is 1) from 11 to 35 (increase is 35 - 11, which is 24) and the smallest of those increases is 1, so the function returns 1 in this example. ** ASK YOUR INSTRUCTOR FOR HELP ** ** if these examples and the above specification are not clear to you. ** Type hints: :type numbers: list[int] | tuple[int] """ smallest = numbers[1] - numbers[0] for k in range(1, len(numbers) - 1): increase = numbers[k + 1] - numbers[k] if increase < smallest: smallest = increase return smallest def run_test_two_d_smallest_increase(): """ Tests the two_d_smallest_increase function. """ print() print('--------------------------------------------------') print('Testing the two_d_smallest_increase function:') print('--------------------------------------------------') format_string = ' two_d_smallest_increase( {} )' test_results = [0, 0] # Number of tests passed, failed. sequence_of_sequences = ([10, 15, 3, 20, 22, 28, 20, 11], [-4, -10, 20, 5], [2, 5, 10, 11, 35], [2, 5, 10, 11, 35]) expected = [-12, -15, 1, 1] print_expected_result_of_test([sequence_of_sequences], expected, test_results, format_string) actual = two_d_smallest_increase(sequence_of_sequences) print_actual_result_of_test(expected, actual, test_results) # Test 2: Same as previous test, but using tuples sequence_of_sequences = ((10, 15, 3, 20, 22, 28, 20, 11), (-4, -10, 20, 5), (2, 5, 10, 11, 35), (2, 5, 10, 11, 35)) expected = [-12, -15, 1, 1] print_expected_result_of_test([sequence_of_sequences], expected, test_results, format_string) actual = two_d_smallest_increase(sequence_of_sequences) print_actual_result_of_test(expected, actual, test_results) # Test 3: sequence_of_sequences = ((25, 18, 20, 18, 25, 30, 20, 30, 25), (2, 5, 10, 11, 35)) expected = [-10, 1] print_expected_result_of_test([sequence_of_sequences], expected, test_results, format_string) actual = two_d_smallest_increase(sequence_of_sequences) print_actual_result_of_test(expected, actual, test_results) # Test 3: sequence_of_sequences = ((25, 18, 20, 18, 25, 30, 20, 30, 25), (2, 5, 10, 11, 35)) expected = [-10, 1] print_expected_result_of_test([sequence_of_sequences], expected, test_results, format_string) actual = two_d_smallest_increase(sequence_of_sequences) print_actual_result_of_test(expected, actual, test_results) # Test 4: sequence_of_sequences = ((25, 18, 20, 18, 25, 30, 20, 30, 25),) expected = [-10] print_expected_result_of_test([sequence_of_sequences], expected, test_results, format_string) actual = two_d_smallest_increase(sequence_of_sequences) print_actual_result_of_test(expected, actual, test_results) # Test 5: sequence_of_sequences = ((25, 35),) expected = [10] print_expected_result_of_test([sequence_of_sequences], expected, test_results, format_string) actual = two_d_smallest_increase(sequence_of_sequences) print_actual_result_of_test(expected, actual, test_results) # Test 6: sequence_of_sequences = ((35, 25),) expected = [-10] print_expected_result_of_test([sequence_of_sequences], expected, test_results, format_string) actual = two_d_smallest_increase(sequence_of_sequences) print_actual_result_of_test(expected, actual, test_results) # SUMMARY of test results: print_summary_of_test_results(test_results) def two_d_smallest_increase(sequence_of_subsequences): """ What comes in: A non-empty sequence of subsequences of numbers, where each subsequence has length at least 2. What goes out: A list whose length is the same as the number of subsequences, where the Jth item in the list is the smallest increase in the Jth subsequence (and "smallest increase" is defined as in the previous problem). Side effects: None. Examples: two_d_smallest_increase( ( [10, 15, 3, 20, 22, 28, 20, 11], [-4, -10, 20, 5], [2, 5, 10, 11, 35], [2, 5, 10, 11, 35] ) returns [-12, , -15, 1, 1] (Note that the subsequences here are the examples used in the previous problem -- see that problems for why the smallest increases of the four subsequences are -12, -15, 1 and 1, respectively.) ** ASK YOUR INSTRUCTOR FOR HELP ** ** if these examples and the above specification are not clear to you. ** Type hints: :type sequence_of_subsequences: tuple[list[int]] | tuple[tuple[int]] """ new = [] for k in range(len(sequence_of_subsequences)): subsequence = sequence_of_subsequences[k] new.append(smallest_increase(subsequence)) return new def run_test_sum_bigger_than_average(): """ Tests the sum_bigger_than_average function. """ print() print('--------------------------------------------------') print('Testing the sum_bigger_than_average function:') print('--------------------------------------------------') format_string = ' sum_bigger_than_average( {} )' test_results = [0, 0] # Number of tests passed, failed. # Test 1: numbers = ([5, 1, 8, 3], [0, -3, 7, 8, 1], [6, 3, 5, 5, -10, 12]) expected = 5 + 8 + 7 + 8 + 6 + 5 + 5 + 12 # which is 56 (A = 17/4 = 4.25) print_expected_result_of_test([numbers], expected, test_results, format_string) actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 2: numbers = ([5, 1, 1, 1, 1, 3], [1, 4, 4, 1, 1, 1, 1], [6, 3, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 2, 1]) # so A = 12/6 = 2 and expected = 5 + 3 + 4 + 4 + 6 + 3 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 3 # = 70 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 3: numbers = ([5, 1, 1, 1, 1], [1, 6, 5, 1, 1, 1, 1], [6, 3, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [5, 6, 7, 8, 9, 10, 11, 12]) expected = 151 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 4: numbers = ([1, 2, 1, 1, 1], [1, 6, 5, 1, 1, 1, 1], [6, 3, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [5, 6, 7, 8, 9, 10, 11, 12]) expected = 148 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 5: numbers = ([100, 200, 1, 1, 1], [1, 6, 5, 1, 1, 1, 1], [6, 3, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5], [5], [5, 6, 7, 8, 9, 10, 11, 12]) expected = 300 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 6: numbers = ([100, 200, 99], [300]) expected = 500 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 7: numbers = ([98, 200, 99], [300]) expected = 500 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 8: numbers = ([100, 200, 99], [50]) expected = 200 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 9: numbers = ([-4], [], [], [-3, 0, 1, 2, 3], [-3.99], [-4.0000000001]) expected = -0.99 # from -3 + 0 + 1 + 2 + 3 + (-3.99) print_expected_result_of_test([numbers], expected, test_results, format_string, suffix="(approximately)") actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results, precision=6) # Test 10: numbers = ([-99999999999], [], []) expected = 0 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 11: numbers = ([1, 4], [3, 3, 3, 3], [], [2.49, 2.48, 2.49], []) expected = 4 + 3 + 3 + 3 + 3 # = 16 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results) # Test 12: numbers = ([1, -1],) expected = 1 print_expected_result_of_test([numbers], expected, test_results, format_string) actual = sum_bigger_than_average(numbers) print_actual_result_of_test(expected, actual, test_results) # SUMMARY of test results: print_summary_of_test_results(test_results) def sum_bigger_than_average(numbers): """ What comes in: A non-empty sequence of sequences of numbers, with the first sub-sequence being non-empty. What goes out: Returns the sum of all the numbers in the subsequences that are bigger than A, where A is the average of the numbers in the FIRST sub-sequence. Side effects: None. Examples: Suppose that numbers is: ([5, 1, 8, 3], [0, -3, 7, 8, 1], [6, 3, 5, 5, -10, 12]) Then: the average of the numbers in the first sub-sequence is (5 + 1 + 8 + 3) / 4, which is 17 / 4, which is 4.25, and so sum_bigger_than_average(numbers) returns (5 + 8 + 7 + 8 + 6 + 5 + 5 + 12), which is 56, since the numbers in that sum are the numbers in the subsequences that are bigger than 4.25. ** ASK YOUR INSTRUCTOR FOR HELP ** ** if this example and the above specification are not clear to you. ** """ ########################################################################### # TODO: 6. Implement and test this function. # Tests have been written for you (above). ########################################################################### ########################################################################### # ------------------------------------------------------------------------- # DIFFICULTY AND TIME RATINGS (see top of this file for explanation) # DIFFICULTY: 7 # TIME ESTIMATE: 15 minutes. # ------------------------------------------------------------------------- ############################################################################### # Our tests use the following to print error messages in red. # Do NOT change it. You do NOT have to do anything with it. ############################################################################### def print_function_call_of_test(arguments, test_results, format_string): testing_helper.print_function_call_of_test(arguments, test_results, format_string) def print_expected_result_of_test(arguments, expected, test_results, format_string, suffix=''): testing_helper.print_expected_result_of_test(arguments, expected, test_results, format_string, suffix) def print_actual_result_of_test(expected, actual, test_results, precision=None): testing_helper.print_actual_result_of_test(expected, actual, test_results, precision) def print_summary_of_test_results(test_results): testing_helper.print_summary_of_test_results(test_results) # To allow color-coding the output to the console: USE_COLORING = True # Change to False to revert to OLD style coloring testing_helper.USE_COLORING = USE_COLORING if USE_COLORING: # noinspection PyShadowingBuiltins print = testing_helper.print_colored else: # noinspection PyShadowingBuiltins print = testing_helper.print_uncolored # ----------------------------------------------------------------------------- # Calls main to start the ball rolling. # The try .. except prevents error messages on the console from being # intermingled with ordinary output to the console. # ----------------------------------------------------------------------------- try: main() except Exception: print('ERROR - While running this test,', color='red') print('your code raised the following exception:', color='red') print() time.sleep(1) raise