Section 2. Functions, Strings, and Grids


Section materials curated by Zheng Lian, drawing upon materials from previous quarters.

Written by Juliette Woodrow, Brahm Capoor, Parth Sarin, And Zheng Lian

If you'd like to try your solutions in PyCharm, download a starter project to import here. We've included some doctests for you to test with, but you should also add more.


Questions About Doctests

In class this week, we discussed doctests: ways of specifying the expected output of a function on certain parameters, which provide a convenient way of testing our functions as we write them. Doctests are an incredibly effective tool for programmers, but require careful consideration as we write them. As you go through the quarter, you'll develop a stronger sense of how to test your code, but it's never to early to start thinking about it. While you go through your section problems, consider adding doctests to ensure your code handles all inputs properly.

Syntax for Doctests:

            
>>> name_of_function(param1, param2)
'output of function goes here'
            
          

As shown above, the syntax is three greater than signs followed by a space and then the name of the function and the specific parameters you want to test. On the next line you put the output you expect from those parameters. To run a doctest, right click on the greater than signs and hit "Run 'Doctest name_of_function'".



Opening the Black Box

In this program, you will tackle a series of problems intended to increase your familiarity with parameters and return statements. Implement the following functions and include at least one doc test per function:

  • def in_range(n, low, high), which takes in three integer parameters and returns True if n is between low and high (inclusive of both ends of the range) and False otherwise.
  • def is_even(n), which takes in an integer parameter n and returns True if n is even and False. You may wish to use the % operator, which returns the remainder when dividing one number by the other. For instance, 7 % 3 evaluates to 1, since the remainder when dividing 7 by 3 is 1.
    • Note: to solve this problem you will need to use the % operator, known as the mod operator. Check out the modulus section of the Python reader. Mod will not be on the first quiz.
  • def only_one_even(num1, num2), which takes in two integer parameters and returns True if and only if exactly one of them is even.
  • (challenge) def is_prime(n), which takes in an integer parameter n and returns True if n is prime and False otherwise. As a reminder, a prime number is a number which has no factors other than 1 and itself.
def in_range(n, low, high):
    if n >= low and n <= high:
        return True 
    return False

def is_even(n):
    if n % 2 == 0:
        return True 
    return False

def only_one_even(num1, num2):
    if (num1 % 2 == 0 and num2 % 2 == 1) or (num1 % 2 == 1 and num2 % 2 == 0):
        return True 
    return False

def longer_str(str1, str2):
    if len(str1) > len(str2):
        return str1
    return str2

def is_phone_number(str1):
    if not str1.isdigit():
        return False
    if len(str1) != 9 and len(str1) != 10:
        return False
    return True

def is_prime(n):
    # Note that there are more efficient solutions to this problem!
    if n <= 1:
        return False
    for i in range(2, n):
        if n % i == 0:
            return False
    return True



Playing with Strings

Remove All Occurrences

Write the following function: def remove_all_occurrences(s, to_remove) which removes all occurences of the length-one string to_remove from the string s. Do not use the replace function, instead build up a new string. Here are some sample inputs and outputs for this function:

            
>>> remove_all_occurrences('This is a test', 't')
'This is a es'
>>> remove_all_occurrence('----O----', '-')
'O'
            
          

Palindrome Checker

Write the following function: def is_palindrome(s) which returns True if s is a palindrome and False otherwise.

We say that a word is a palindrome if it reads the same forwards as backwards. For example, "Abba" is a palindrome because it is the same word read forwards and backwards. Here are some more examples:

  • racecar
  • kayak
  • mr owl ate my metal worm

Here are some examples of Palindromes in other languages:

  • حلب قلعة تحت تعلق ب (Dates hang underneath a castle in Halab)
  • 여보, 안경 안보여 (Honey, I can't see my glasses)
  • कड़क (a loud thunderous sound)

Here are some sample inputs and outputs for this function:

            
  >>> is_palindrome('juliette')
  False
  >>> is_palindrome('maps spam')
  True
  >>> is_palindrome('Maps spam')
  False # uppercase 'M' and lowercase 'm' are not the same character
            
          

Exclaim

Juliette loves to type text messages with lots of punctuation. She's very enthusiastic, so she'll often repeat the exclamation a bunch... Here's one of her recent text conversations:

            Juliette: "Did you see Amanda Gorman at the inauguration?!?!?!?!"
            "Yes, her poem was great. Did you like it?"
            Juliette: "It was wicked cool!!!"
            "Agreed! And she is only 22. What will you have accomplished by the age of 22?"
            Juliette: "......."

Juliette is getting tired of repeating the punctuation so much. Help her out by writing a Python function that does it for her! The function should accept a message, msg, the ending punctuation, end, and the number of times to repeat the punctuation, n. The function definition looks as follows: def excalim(msg, end, n) The function should print out the resulting message to the terminal, so Juliette can copy it and paste it into her text messages. For example, calling exclaim('Did you see Amanda Gorman at the inauguration', '?!', 6) would print Did you see Amanda Gorman at the inauguration?!?!?!?!?!?! and calling exclaim('106A is awesome', '!', 5) would print 106A is awesome!!!!!.

def remove_all_occurrences(s, to_remove):
    result = ''
    for i in range(len(s)):
        if s[i] != to_remove:
            reuslt += s[i]
    return result

def is_palindrome(s):
    result = ''
    # This is not the most efficient way. Can you think of a better one?
    for i in range(len(s)):
        if s[i] != s[len(s) - i - 1]
            return False
    return True
                
def exclaim(msg, end, n):
    """
    Prints out the message with an exclamatory
    ending which is printed n number of times.

    Arguments:
    msg -- The message to print out.
    end -- The exclamation to add to the end of the message.
    n   -- The number of times to print the exclamation.
    """
    output = msg

    for i in range(n):
        output += end

    print(output)
                
            



Grids

Bubble Up

This is straight from an old CS106A midterm :) Grids will not be on the first quiz.

Suppose there is a grid where every square is either a bubble 'b', rock 'r', or empty None. Write code for a bubble_up(grid, y) function that tries to move every bubble in a row up one square as follows: given a grid and an in-bounds y value. Look at every square with that y. If the square contains a bubble 'b', and the square above it is empty, move the bubble up one square, changing its original square to be empty.

Here is an example run of bubble_up(grid, y) for the row y=1 in Doctest format:

            
>>> grid = Grid.build([[None, 'r', 'b'], ['b', 'b', 'b']])
>>> bubble_up(grid, 1)
[['b', 'r', 'b'], [None, 'b', 'b']]
def bubble_up(grid, x, y):
    """
    >>> can_bubble_up(grid, 0, 1)
    True
    >>> can_bubble_up(grid, 0, 0)
    False
    >>> can_bubble_up(grid, 2, 1)
    False
    """
    # check if the square is a bubble
    if grid.get(x, y) != 'b':
        return False

    # check if the square above it is in bounds and empty
    if not grid.in_bounds(x, y-1) or grid.get(x, y-1) != None:
        return False

    # we know it can be bubbled up if we have made it here
    return True