Skip to content

Monday 9/25

List, Tuples, Dictionaries, Sets

When to use each

  • list - Order matters, duplicates allowed, access by index, mutable (changeable)
  • tuple - Order matters, duplicates allowed, access by index, immutable (un-changeable)
    • Tuples are used to provide the effect of multiple return values for functions
  • dict - A collection of key/value pairs. No duplicate keys are allowed, order doesn't matter.
  • set - No duplicates allowed, order doesn't matter.

Accessing Docstrings

Each collection type has built-in methods. Documentation can be accessed by using help in the shell:

class list(object)
 |  list(iterable=(), /)
 |  
 |  Built-in mutable sequence.
 |  
 |  If no argument is given, the constructor creates a new empty list.
 |  The argument must be an iterable if specified.
 |  
 |  Methods defined here:
 |  
 |  __add__(self, value, /)   Each of the entries with double underscores
 |      Return self+value.    corresponds to an operator. For example __add__
 |                            describes how the + operator works for lists.
 |  
 |  append(self, object, /)
 |      Append object to the end of the list.
 |  
 |  clear(self, /)
 |      Remove all items from list.
 |  
 |  copy(self, /)
 |      Return a shallow copy of the list.
 |  
 |  count(self, value, /)
 |      Return number of occurrences of value.
 |  
 |  extend(self, iterable, /)
 |      Extend list by appending elements from the iterable.
 |  
 |  index(self, value, start=0, stop=9223372036854775807, /)
 |      Return first index of value.
 |      
 |      Raises ValueError if the value is not present.
 |  
 |  insert(self, index, object, /)
 |      Insert object before index.
 |  
 |  pop(self, index=-1, /)
 |      Remove and return item at index (default last).
 |      
 |      Raises IndexError if list is empty or index is out of range.
 |  
 |  remove(self, value, /)
 |      Remove first occurrence of value.
 |      
 |      Raises ValueError if the value is not present.
 |  
 |  reverse(self, /)
 |      Reverse *IN PLACE*.
 |  
 |  sort(self, /, *, key=None, reverse=False)
 |      Sort the list in ascending order and return None.
 |      
 |      The sort is in-place (i.e. the list itself is modified) and stable (i.e. the
 |      order of two equal elements is maintained).
 |      
 |      If a key function is given, apply it once to each list item and sort them,
 |      ascending or descending, according to their function values.
 |      
 |      The reverse flag can be set to sort in descending order.

The Containment Operator

Containment checking can be performed with in for all Collection types:

# Lists: 
colors = ["red", "blue", "green"]

"red" in colors   # True
"pink" in colors  # False

# Tuples: 
hats = ("fedora", "fez")

"fez" in colors  # True
"cap" in colors  # False

# Dictionaries:
ages = {"Jan": 13, "Milo": 15}

"Jan" in ages  # True
13 in ages     # False-- For dictionaries, containment operator acts on the keys, not values!

Collections Lab

In this lab you will write functions that involve working with Python collection classes. One of the goals today is to make sure that you are in the habit of testing locally and using flake8 to verify that your formatting is correct. To that end, the Gradescope autograder will only provide two free submissions. Additional submissions will result in a small point deduction.

Part 1 - Counter

One common use of dictionaries is to maintain a collection of counters. For example, we might want to keep track of the number of absences for students in a computer science course. Each time a student is absent, the appropriate counter should incremented by one. In this case, the key is the students name and the value is the total number of absences. Write a function named increment_counter that takes a dictionary and a student name as arguments. If the student isn't already in the dictionary, he or she should be added with a count of 1. If he or she is already in the dictionary, the current count should be increased by one. In either case, the function should return the updated count for that student. Your function must be in a file named counter.py. The following interaction illustrates the expected behavior:

>>> counts = dict()
>>> increment_counter(counts, "Alice")
1
>>> counts
{'Alice': 1}
>>> increment_counter(counts, "Alice")
2
>>> counts
{'Alice': 2}
>>> increment_counter(counts, "Zed")
1
>>> counts
{'Alice': 2, 'Zed': 1}

Don't submit until you are confident that your functionality is correct and your docstrings are complete and properly formatted! Here are the instructions for installing and configuring flake8 and the docstring requirements:

Part 2 - Neighbors

Create a file named neighbors.py. This functions will contain two functions get_adjacent and get_neighbors. First, complete and test get_adjacent, then work on get_neighbors. You do not need to complete docstrings for these functions.

get_adjacent

The get_adjacent function must take two arguments: the first will be a list, and the second will be an integer value representing an index. It must return a new list containing the two elements immediately to the left and right of the provided index. If the provided index is at either the beginning or end of the list, there will be only one element in the list. If the provided the provided list only has one element, then there are no adjacent items and the returned list will be empty.

The following function can be used to test your implementation:

def test_get_adjacent():
    """Test the get_adjacent method."""
    items = ["A", "B", "C", "D"]

    # Easy cases where there are two adjacent
    assert get_adjacent(items, 1) == ["A", "C"]
    assert get_adjacent(items, 2) == ["B", "D"]

    # Trickier cases where there is only one adjacent
    assert get_adjacent(items, 0) == ["B"]
    assert get_adjacent(items, 3) == ["C"]

    # Case where there are no adjacent
    short = ["X"]
    assert get_adjacent(short, 0) == []

You can call it from your main block as follows:

if __name__ == "__main__":
    test_get_adjacent()

get_neighbors

As part of your work for a political campaign you need to create a mailing list that includes the neighbors of known donors to your party. Create a function named get_neighbors that takes two arguments: the first is a list of mailing addresses that is ordered according to the positions of houses on a particular street. The second is a string representing the addresses of one of the houses from the list. Your function must return a new list containing the immediate neighbors of the provided address. Don't code this function from scratch. You should be able to use the index method of the provided list along with the get_adjacent function you already completed. It should be possible to write your function so that it only contains a single line. Here is a testing function that you can use to evaluate your finished code:

def test_get_neighbors():
    """Test the get_neighbors method."""
    homes = ["121 Main", "123 Main", "125 Main", "127 Main"]

    # Easy cases where there are two neighbors
    assert get_neighbors(homes, "123 Main") == ["121 Main", "125 Main"]
    assert get_neighbors(homes, "125 Main") == ["123 Main", "127 Main"]

    # Trickier cases where there is only one neighbor
    assert get_neighbors(homes, "121 Main") == ["123 Main"]
    assert get_neighbors(homes, "127 Main") == ["125 Main"]

    # Case where there are no neighbors
    short_street = ["237 Broad"]
    assert get_neighbors(short_street, "237 Broad") == []