Learning objective: Apply control structures and data structures to solve problems involving numbers, text, and files.

  • hw1.py is the file to put your implementations for each problem. hw1.py is not a runnable program, so we don’t use the main-method pattern.

  • hw1_test.py is the file for you to put your own tests. The Run button executes this program.

  • cse163_utils.py is a helper file that has code to help you test your code.

Useful CSE 163 Resources

Expectations: In hw1.py you should not use any import statements or features in Python we have not yet discussed in class, section, or HW specs. All of these problems should be solved using the fundamental constructs we’ve learned in class so far. For your testing program, you can use imports (especially to use cse163_utilsassert_equals function.

total and test_total

The total function inside hw1.py and the test_total function inside hw1_test.py exist only for your reference. You aren’t required to modify either function but should use them as examples for how to structure your functions inside hw1.py and hw1_test.py, respectively.

Additionally, you should pay attention to how the comment for total mentions any special behavior that might not be obvious to someone who’s seeing the code for the first time. Keep this in mind as you document the other functions in this assessment.

count_divisible_digits

📝 Task: Write a function count_divisible_digits that takes two integer numbers n and m as arguments and returns the number of digits in n that are divisible by m. If m is 0, then count_divisible_digits should return 0. For this problem, any digit in n that is 0 is divisible by any number. You may assume m is a single digit (0 ≤ m <10) and that it is not negative.

  • count_divisible_digits(650899, 3) returns 4 since the digits 0, 6, and 9 are all divisible by 3.

  • count_divisible_digits(-204, 5) returns 1 since 0 is divisible by 5.

  • count_divisible_digits(24, 5) returns 0.

  • count_divisible_digits(1, 0) returns 0.

Do not use str to solve this problem in any way to solve any part of the problem. Instead, you should solve this problem by manipulating the number itself using integer division.

  • n // 10 evaluates to all but the last digit of n.

  • n % 10 evaluates to the last digit of n.

📝 Task: Write a test that calls the function with some inputs and compares the output of the program with the expected value using assert_equals. Include test cases for all of the examples above as well as 2 additional test cases.

is_relatively_prime

📝 Task: Write a function is_relatively_prime that takes two integer numbers n and m, returning True if n and m are relatively prime to each other and False otherwise. Two numbers are relatively prime if they share no common factors besides 1. (1 is relatively prime with every number.) Assume the value of n and m are at least 1.

  • is_relatively_prime(12, 13) returns True since the factors of 12 are 1, 2, 3, 4, 6, 12 and the factors of 13 are 1, 13.

  • is_relatively_prime(12, 14) returns False since the factors of 12 are 1, 2, 3, 4, 6, 12 and the factors of 14 are 1, 2, 7, 14.

  • is_relatively_prime(5, 9) returns True since the factors of 5 are 1, 5 and the factors of 9 are 1, 3, 9.

  • is_relatively_prime(8, 9) returns True since the factors of 8 are 1, 2, 4, 8 and the factors of 9 are 1, 3, 9.

  • is_relatively_prime(8, 1) returns True since we define that 1 is relatively prime with every number.

Do not use data structures to store factors during the execution of the algorithm, and use a single loop rather than nested loops.

📝 Task: Write a test that calls the function with some inputs and compares the output of the program with the expected value using assert_equals. Include test cases for all of the examples above as well as 2 additional test cases.

travel

📝 Task: Write a function travel which takes a string of north, east, south, west directions, a starting location on a grid x, and a starting location on a grid y. Your function should return a tuple that indicates the new position after following the directions starting from the given x, y. The returned tuple should be in the format (x_new, y_new).

The directions string will use 'N' to indicate increasing the y-coordinate, 'E' to indicate increasing the x-coordinate, 'S' to indicate decreasing the y-coordinate, and 'W' to indicate decreasing the x-coordinate. The case of the characters should be ignored. You can assume that x and y are both of type int. Any characters that are not 'N', 'E', 'W', or 'S' (ignoring letter-casing) should be ignored.

travel('NW!ewnW', 1, 2) should return the tuple (-1, 4) following this sequence of movements:

  1. Start at (1, 2).

  2. Move 'N' to (1, 3).

  3. Move 'W' to (0, 3).

  4. Ignore '!' since it is not a valid direction.

  5. Move 'e' to (1, 3).

  6. Move 'w' to (0, 3).

  7. Move 'n' to (0, 4).

  8. Move 'W' to (-1, 4).

📝 Task: Write a test that calls the function with some inputs and compares the output of the program with the expected value using assert_equals. Include test cases for all of the examples above as well as 2 additional test cases.

reformat_date

📝 Task: Write a function reformat_date which takes three strings as arguments representing a date, a current date format, and a target date format and returns a new string with the date formatted in the target format.

A date string will be some non-empty string of numbers separated by / (e.g, "3/6/1995"). Note that the numbers between the /‘s can have any number of digits, but you may assume there is at least one digit for each part of the date provided.

The current and target formats will be some non-empty sequence of the characters 'D', 'M', 'Y' separated by /. You can assume the given date and the current format will match up (i.e., they will have the same number of /‘s) and that any date symbol that appears in the target format also appears in the current format (i.e., if the target format contains a 'Y' the current format will also contain a 'Y').

For example, if we made the method call: reformat_date("12/31/1998", "M/D/Y", "D/M/Y"), it should return the string "31/12/1998". In this example, the first argument represents a date and the second argument specifies this date is currently in the format Month/Day/Year (abbreviated "M/D/Y"). The third argument specifies that the method should return a new date in the format of Day/Month/Year format (abbreviated "D/M/Y").

Below are some valid/invalid examples of current and target formats. You do not need to handle invalid formats. You may assume we will never pass you an example that is invalid.

  • Valid: Date - "1/2/3", Current Format - "M/D/Y", Target Format - "Y/M/D". It should return "3/1/2".
  • Valid: Date - "0/200/4", Current Format - "Y/D/M", Target Format - "M/Y". It should return "4/0".
  • Valid: Date - "3/2", Current Format - "M/D", Target Format - "D". It should return "2".
  • Invalid: Date - "3/2", Current Format - "M/D/Y", Target Format - "Y/M/D"
    • Reason: The date and the current format don’t have the same number of parts.
  • Invalid: Date - "3/2", Current Format - "M/D", Target Format - "Y/M/D"
    • Reason: Target contains a part of a date ("Y") not in the current format ("M/D").
  • Invalid: Date - "1/2/3/4", Current Format - "M/D/Y/S", Target Format - "M/D"
    • Reason: Date format contains a part that is not 'M', 'D', or 'Y'.
  • Invalid: Date - "", Current Format - "", Target Format - "" (an empty string)
    • Reason: An empty string.

Again, you may assume we won’t pass you any of these invalid date formats. We wanted to provide this list and rationale for why they are invalid to give you a better sense of what assumptions you can make about your inputs.

📝 Task: Write a test that calls the function with some inputs and compares the output of the program with the expected value using assert_equals. Include test cases for all of the valid examples above (there should be four of them) as well as 2 additional test cases.

Your function should be as general as possible and avoid hard-coding specific orderings of the date parts.

longest_word

📝 Task: Write a function longest_word that takes a string filename and returns the longest word in the file with which line it appears on. A word here is defined as a sequence of characters separated by whitespace. If there are ties for the longest word, it should return the one that appears first in the file. If the file is empty or there are no words in the file, the function should return None. Assume that the file exists. Consider a file song.txt with the following contents.

Row, row, row your boat
Gently down the stream
Merrily, merrily, merrily, merrily
Life is but a dream!

Then the call longest_word('/home/song.txt') should return '3: Merrily,'.

📝 Task: Write a test that calls the function with some inputs and compares the output of the program with the expected value using assert_equals. Include test cases for all of the examples above as well as 2 additional test cases.

Hint

Create new files in your workspace for each additional test case. When specifying file names, use absolute paths, such as /home/song.txt.

get_average_in_range

📝 Task: Write a function get_average_in_range that takes a list of integers, an integer low, and an integer high, and returns the average of all values within the list that lies in the given range from low (inclusive) to high (exclusive). If there are no values in the given range, returns 0.

  • get_average_in_range([1, 5, 6, 7, 9], 5, 7) returns 5.5 since only 5 and 6 fall in the range between 5 (inclusive) and 7 (exclusive), and the average of 5 and 6 is 5.5.

  • get_average_in_range([1, 2, 3], -1, 10) returns 2.0 since 1, 2, 3 all fall within the specified range and the average of the three numbers is 2.0.

📝 Task: Write a test that calls the function with some inputs and compares the output of the program with the expected value using assert_equals. Include test cases for all of the examples above as well as 2 additional test cases.

mode_digit

📝 Task: Write a function mode_digit that takes an integer number n and returns the digit that appears most frequently in that number. The given number may be positive or negative, but the most frequent digit returned should always be non-negative. If there is a tie for the most frequent digit, the digit with the greatest value should be returned.

  • mode_digit(12121) returns 1.

  • mode_digit(0) returns 0.

  • mode_digit(-122) returns 2.

  • mode_digit(1211232231) returns 2.

Hint

Use data structures to count digit occurrences.

  • Do not create strings in any way to solve any part of the problem.

  • Do not use any nested loops or recursion.

  • Do not use an if, elif, or else branch for each digit. You can still use if/elif/else in general for other purposes.

    # Avoid doing this
    if digit == 0:
        ... # do something with 0
    elif digit == 1:
        ... # do something with 1
    ...
    

📝 Task: Write a test that calls the function with some inputs and compares the output of the program with the expected value using assert_equals. Include test cases for all of the examples above as well as 2 additional test cases.

Code Quality

Assessment submissions should pass these checks: flake8, and code quality guidelines. The code quality guidelines are very thorough. For this assessment, the most relevant rules can be found in these sections:

Note

Make sure to provide a descriptive file header in docstring format, not something generic like “implements functions for Primer”.

Submission

Submit your work by pressing the Mark button. Submit as often as you want until the deadline for the initial submission. You can view your past submissions using the “Submissions” button.

Please make sure you are familiar with the resources and policies outlined in the syllabus and the take-home assessments page.

THA 1 - Primer

Initial Submission by Thursday 07/07 at 11:59 pm.

Submit on Ed