Homework 7: Shawn and Todd’s Election Extravaganza

Due: Tuesday April 14, 2020 at 9:00PM EDT.

Setup and Handin

Setup

Handin

Remember your resources!

The Assignment

If you know how to solve any of these problems using techniques you’ve learned outside of 111, don’t! Make sure to only use Python concepts we’ve talked about in class.

Create a new Python file called hw7_code.py.

Sheriff Todd’s Election

An election is happening in the out-west Far Far Away region, and Sheriff Todd needs help counting the votes. Deputy Shawn is making a mess in the election between Shr Ek and Don Key, and he needs your help to ensure a peaceful transition of power!

For the following, you can assume a vote is just the name of a candidate (though capitalization might be inconsistent!)

  1. Task: Write a function name_matches that takes a vote (string) and a name (string) and returns a boolean indicating whether the vote is for the given name, regardless of how the vote and name have been capitalized (that is, ignore case).

    Note: You can lowercase a string s in Python by writing s.lower() (where s gets replaced by the string you want to lowercase). As in Pyret, you have Boolean operators and, or, and not.

  2. Task: Write a function any_votes_for that takes a name (string) and votes (list of votes) and returns a boolean indicating whether any votes were for the given name (case insensitive).

  3. Task: Write a function count_votes_for that takes a name (string) and a votes, a list of votes, and returns the number of votes that were for the given name (case insensitive).

  4. Task: Write a function got_more_votes that takes two names, name_one and name_two, and votes, a list of votes, and returns the name that got more votes (case insensitive). If there is a tie, return the string “Tie”.

  5. Task: Write a function record_vote that takes in votes, a list of votes, and new_vote, a new vote, and adds the vote to the end of the list. This function should not return anything!

  6. Task: Write a function percentage_votes that takes a name and a list of votes and returns the percentage of votes that match (case insensitive) the given name. You should return the percent in decimal form (i.e. if the name matches 90% of the votes, return 0.9). Please round to the nearest tenth. Don’t forget to consider the case where someone has no votes (or where there are no votes)!

    Rounding help!

    You can round a number in Python using the round function. The round function has two arguments, the first being the number to round and the second representing how many decimal places to have. Here are a few examples:

    # If you'd like to round to the nearest whole number
    # Note: this will still produce a decimal not an Int
    
    round(1.3446, 0)     # produces 1.0
    round(1.5111, 0)     # produces 2.0
    round(1.7934, 0)     # produces 2.0
    
    # If you'd like to round to the nearest tenth
    
    round(1.3446, 1)     # produces 1.3
    round(1.5111, 1)     # produces 1.5
    round(1.7934, 1)     # produces 1.8
    
    # If you'd like to round to the nearest hundreth
    
    round(1.3446, 2)     # produces 1.34
    round(1.5111, 2)     # produces 1.51
    round(1.7934, 2)     # produces 1.79
    round(1.799, 2)      # produces 1.8
    
  7. Task: Write a function test_votes to test your vote functions. In particular, think about how to test record_vote. Run test_votes() to make sure all your tests pass and your functions work as expected.

Note: Any time you are returning a name, it may be returned lowercased or uppercased. Our test suite is case insensitive, so returning "Credo" will be treated the same as "credo" and "CREDO". Same applies for functions that return lists. ["Cre","Credo"] will be treated the same as ["cre","CREDO"].

Sorting Lists in Python

Here we have a lot of information to help with these questions. They’ll be quite difficult to do without reading these first.

String slicing

To do many of the following problems, you will need to do something called string slicing. String slicing is the Python equivalent of Pyret’s string-substring, but winds up being a lot more powerful.

Let’s say you have the string str = "Beep!". Just like in Pyret, strings in Python are 0-indexed:

To access the characters at those indices, use the notation: str[index]. For example,

>>> str[0]
"B"
>>>str[4]
"!"

If you want to slice a string into a substring of more than one character, use the notation: str[start:end] where start represents the first index of the substring (inclusive) and end represents the last index of the substring (exclusive). For example,

>>> str[0:5]
"Beep!"
>>> str[1:4]
"eep"
>>> str[2:3]   # note that this is equivalent to str[2]
"e"
>>> str[2:2]   # no characters in range, so this outputs the empty string
""

That’s all you need to know for this assignment, but Python has a few additional shortcuts for string slicing that might be useful in the long run:

Basic sorting

Python has a useful and customizable sorting function that operates on lists. In this section, we will explore how to use it.

The simplest version of the function is sorted(lst: list), which takes in a list and sorts it in ascending order.

For example:

>>> sorted([1,5,3,1])
[1,1,3,5]

>>> sorted(["bc", "abc", "d", "aa", "aaa"])
['aa', 'aaa', 'abc', 'bc', 'd']

>>> sorted([False, True, True, False, True])
[False, False, True, True, True]

To sort a list in descending order, add the input reverse=True to the function call. Here are the examples from above but sorted in reverse:

>>> sorted([1,5,3,1], reverse=True)
[5,3,1,1]

>>> sorted(["bc", "abc", "d", "aa", "aaa"], reverse=True)
['d', 'bc', 'abc', 'aaa', 'aa']

>>> sorted([False, True, True, False, True], reverse=True)
[True, True, True, False, False]

Note: Notation like reverse=True is used for optional inputs to a function, a concept we did not see in Pyret. Since an optional input might not be provided, we need the <name>= part to indicate which optional parameter is being used.

Custom sorting

In most cases, default sorting is enough. However, what if you want to sort a list in a specific, custom way? To do so, add the input key=my_fun where my_fun represents a function that takes in a single list element. my_fun is called on each element in the list, and its output determines the sort order.

Let’s take a look at a concrete example. The following function takes in a string and returns its length:

def key_fun(elem: str):
    return len(elem)

With key_fun defined, we can do the following to sort the list by string length:

>>> sorted(["Bridgette", "does", "love", "sorting", "lists"], key=key_fun)
['does', 'love', 'lists', 'sorting', 'Bridgette']

(Note that since string length is an integer, sorted defaults to sorting the elements in increasing order)

Emergency Organization

Just as the results of the election are about to go out, Deputy Shawn drops all of the ballots on the floor.

For all of the following functions, you can assume that all names have at least three letters. This means that none of your tests cases should have names less than three letters.

  1. Task: Write a function first_three_letters(name: str, votes: list) that takes in a candidate name and all votes and returns a list of all votes for candidates with the same first three letters in their name as name (regardless of capitalization).
  2. Task: Write a function test_first_three to test first_three_letters.
  3. Task: Write a function sort_a(votes: list) that returns votes sorted alphabetically by the first letter in candidate’s names.
  4. Task: Write a function test_a to test sort_a.
  5. Task: Write a function sort_b(votes: list) that returns votes sorted alphabetically by the second letter in candidate’s names. You can assume all strings in votes will be at least two characters long.
  6. Task: Write a function test_b to test sort_b.

Theme Song

30 minutes of Wild Western Music by multiple artists


Brown University CSCI 0111 (Spring 2020)
Do you have feedback? Fill out this form.