CSE 163, Spring 2019: Homework 1: Part 1

Overview

This is the main part of the assignment that will have you implement many small functions in Python.

We recommend reading over this part and Part 2 so that you get into the practice of writing your tests alongside the code you are developing.

For this part you will be using hw1.py. There is a little bit of starter code there for a function called funky_sum. There is an example test in hw1_test.py to test funky_sum.

For all of the following problems, you should add a function with the expected name to hw1.py and implement the function as described. For every problem in this homework, you should make no assumptions about the parameters unless otherwise described. For every problem, you may assume we pass parameters of the expected types described for that problem and that those parameters are not None.

Problem 1: count_divisible_digits

Write a function called count_divisible_digits that takes two integer numbers n and m as an 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. Here are some example calls:

count_divisible_digits(650899, 3)  # returns 4 because 0, 6, 9 and 9 are divisible by 3
count_divisible_digits(-204, 5)    # returns 1 because 0 is divisible by 5
count_divisible_digits(24, 5)      # returns 0
count_divisible_digits(1, 0)       # returns 0

To receive full credit on this problem, you should avoid building up a string containing the digits of the number. Intead, you should solve this problem by manipulating the nunmber itself.

There is a app function for that!

One of the really handy things about Python is that it has a lot of built-in functions to handle a lot of common tasks. Part of writing "Pythonic" (i.e. readable) code is knowing what these functions are so you can make your code simpler to understand. Here is a full list of Python built-in functions and their documentation and below is a list of useful ones for this assignment except the "casting" functions to convert between data-types that we saw in class

Name Description
abs Takes the absolute value of the given number
len Returns the number of elements inside any object that stores multiple elements (string, list, dictionary)
max Returns the largest number of the numbers provided
min Returns the smallest number of the numbers provided
open Opens a file with the given name
print Prints the given object
range Returns a generator that specifies the range of numbers provided
round Rounds the given number
sum Returns the sum of the given values

For example, if you want to call the max function you would write the line:

x = max(1, 7)  # x will store 7

Edit (April 6th):You can assume m is not negative

Problem 2: is_relatively_prime

Write a function called is_relatively_prime that takes two integer numbers n and m and returns True if n and m are relatively prime to each other, returning False otherwise. Two numbers are relatively prime if they share no common factors besides 1. 1 is relatively prime with every number. You may assume that n and m are at least 1 for this problem. Some example calls are shown below where the comment underneath the call shows the factors for each of the given numbers:

is_relatively_prime(12, 13)  # True
# factors of 12 = [1, 2, 3, 4, 6, 12] and factors of 13 = [1, 13]
is_relatively_prime(4, 24)   # False, shares 2 and 4 as common factors
# factors of 4 = [1, 2, 4] and factors of 24 = [1, 2, 3, 4, 6, 8, 12, 24]
is_relatively_prime(5, 9)    # True
# factors of 5 = [1, 5] and factors of 9 = [1, 3, 9]
is_relatively_prime(8, 9)    # True
# factors of 8 = [1, 2, 4, 8] and factors of 9 = [1, 3, 9]
is_relatively_prime(8, 1)    # True
# factors of 8 = [1, 2, 4, 8] and factors of 1 = [1]

Problem 3: travel

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 string that indicates the new position after following the directions starting from the given x, y. The returned string 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 decrease the x-coordinate. The case of the characters should be ignored. Any characters that are not 'N', 'E', 'W', or 'S' (ignoring letter-casing) should be ignored.

travel('NW!ewnW', 1, 2)  # '(-1, 4)'
    
# 'N', (1,2) => (1,3)
# 'W', (1,3) => (0,3)
# '!', ignored
# 'e', (0,3) => (1,3)
# 'w', (1,3) => (0,3)
# 'n', (0,3) => (0,4)
# 'W', (0,4) => (-1,4)

Problem 4: swip_swap

Write a function called swip_swap that takes a string source and characters c1 and c2 and returns the string source with all occurrences of c1 and c2 swapped. You may assume that the c1 and c2 are single characters. Here are some example calls:

swip_swap('foobar', 'f', 'o')  # 'offbar'
swip_swap('foobar', 'b', 'c')  # 'foocar'
swip_swap('foobar', 'z', 'c')  # 'foobar'

Problem 5: compress

Write a function compress which takes a string as an argument and returns a new string such that each character is followed by its count, and any adjacent duplicate characters are removed (replaced by the single character). You may assume the string only contains letters. Here is an example call

compress('cooooooooooooooooolkangaroo')  # 'c1o17l1k1a1n1g1a1r1o2'
compress('aaa') # 'a3'
compress('')  # ''

Problem 6a: longest_line_length

Write a function longest_line_length that takes a string file_name and returns the length of the longest line in the file. The length of the line is just the number of characters in it (whitespace or not). If the file is empty, the function should return None. You may assume the file exists for the given file name.

Suppose we had a file called poem.txt with the contents:

she sells
sea
shells by
the sea shore

Then the following call would return:

longest_line_length('poem.txt')  # 13

In this file, line 2 would have 4 characters because of the new-line character at the end. This is not something you need to think about though since len will return the proper thing for the strings. Because the last line has 13 characters (there is no new-line), the return of this function is 13.

What is None?

In Python, None is a special value that represents "missing data". For those that have taken 143 or beyond, None in Python is the same as null in Java.

What is the difference between 0 and None?

0 is a number that has a value (it's 0) that has meaning in most contexts (i.e. you can add zero to a number and you get back that number). None, on the other hand, is the absence of a value at all! For this problem, we want to be able to differentiate between returning 0, which is a valid digit to return, and some special value to indicate that this function call has no meaningful answer.

What does None do?

Nothing! You can't really do anything with None because it is a value that's missing. For example, if you were to run

x = 3
y = None
z = x + y  # TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'

That seems bad. How do I detect if something is None to avoid this?

All you need is an if statement with a special condition! It looks like:

x = some_method_that_might_return_none()
if x is None:
    # do whatever you need to do in this case
else:
    # you know x is not None, so it will be a valid value!

Problem 6b: longest_word

Write a function longest_word that takes a string file_name and returns the longest word in the file with which line it appears on. 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. You may assume that the file_name describes a file that exists.

Suppose we had a file called poem.txt with the contents:

she sells
sea
shells by
the sea shore

Then the following call would return:

longest_word('poem.txt')  # '3: shells'

Because the longest word is "shell"s and appears on line 3.

Problem 7: mode_digit

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.

To receive full credit, your solution must not use any nested loops or recursion (if you don't know what that is, you aren't using it), and you must have no more than 4 if/elif/else branches. You are allowed to use extra storage to solve this problem. Here are some example calls

mode_digit(12121)       # 1
mode_digit(0)           # 0
mode_digit(-122)        # 2
mode_digit(1211232231)  # 2

Hint

If you want to create a list with N zeroes in, you can write the line

a = [0] * N,
# If N = 3, then a = [0, 0, 0]