A202 / I211 Assignment 10

Table class

Due Thursday, November 11th, 3:00 PM

Pair programming in this assignment if you like. You may choose any partner in your lab, or work on your own if you prefer.

In lab

  1. Download the table.py module containing the Table class presented in lecture this week.
     
  2. Load it into the IDLE editor and run it.
     
  3. Create a table with test data of your choosing
    .
  4. Test each of the table methods using your test data. Try to reason what the result will be before running each test.
     
  5. Add assert statements to the main method to automate your tests.
     
  6. Modify the constructor (__init__) so that the data argument may be a list of strings, in which case the strings are treated as if they were lines in a comma-separated file: they are split at commas to obtain a list of strings.
     
  7. Modify the constructor so that the data argument may be a string, in which case it is taken as the name of a file. The file's lines are read and a list of these lines is substituted for the data argument value. Place this code before that added to detect and deal with data that is a list of strings. In this way the name of a comma-separated-value (CSV) file may be passed as the argument when creating a table and the resulting table will represent the data in the file in a manner similar to importing the file into a spreadsheet. Test this feature by creating a sample CSV file.
     
  8. Add a .copy() method to the class that returns a copy of the current table. The copy should be like the original, but modification of the copy should not change the original. For this and subsequently added methods, add associated assert tests to the main method.
  9. Add a .invert() method to the class that inverts the table (exchanging rows for columns). That is, the nth row becomes the nth column, and visa versa. Unlike the copy method, which leaves the current table unchanged, this method changes the current table.
  10. Add a method .makeDict(columnIndex) that returns a dictionary for which values in the indicated column are keys that are associated with their rows.

By way of example, here are some tests that could be added to the existing main method tests. Make up your own additional tests.

tc = t.copy()
    assert tc.getData() == [[2, True, 'last'], [3, False, 'column']]
    tc.invert()
    assert tc.getData() == [[2, 3], [True, False], ['last', 'column']]
    dict = t.makeDict(2)
    assert dict['last'] == [2, True, 'last']
    t = Table(data=['a,1,2', 'b,3,4'])
    assert t.getData() == [['a', '1', '2'], ['b', '3', '4']]

When you have completed the last exercise above, or 15 minutes before the lab ends, whichever comes first, submit your table.py file as lab 10 in Vincent. Also, before the end of the lab take time to read the assignment below and ask if after some reflection it is not clear what is required.

This lab contains more exercises than you will probably be able to finish during the lab time. You are urged to continue working on these exercises after your lab and before looking at the solution that will be posted shortly after lab. It is the best preparation for doing the assignment independently. Of course you are encouraged to work on these exercises with others, but are only allowed to work with your partner on the assignment.

Assignment

In this assignment you will be extending the table class developed in lab by making initially empty tables useful and adding two additional methods to the class.

  1. The first step in this assignment is to allow rows or columns to be added to an initially empty table. For convenience, in the table constructor (its __init__ method), make the data parameter a keyword parameter that defaults to the empty list. So for example, Table() is equivalent to Table([]).

    Motivation: Adding rows or columns to the table class as given in lecture and extended in lab requires that the length of the row or column be consistent with the length of existing rows or columns in the table. This means you cannot create an empty table and do anything meaningful with it. So, for example, it is not possible to build up a table from scratch by adding rows or columns with an accumulator loop.

    Hints

    1. Besides extensive modification of the constructor, this also requires modification of the addColumn method. Confirm by inspection of the code that no other changes are needed.
    2. Be careful to avoid the mistake pointed out in class of mutating a default value.
       
  2. Add a .project(columnIndices) method that takes a list of column indices and returns a new table whose columns are those in the current table indicated by the given indices.

    Motivation: Tables may have a great many columns and it is valuable to be able to restrict attention to just the columns of interest for a particular use. Most databases are based on tables and this is a very common database operation.

    Hint: use the ability developed in part 1 to start with a new empty table and add the indicated columns to it.
     

  3. Add a .select(rowPredicate) method that takes as its argument a function rowPredicate of one argument that returns a boolean value. Return a new table that is like a copy of the current table, but with only those rows for which rowPredicate returns true when passed the row as its argument.

    Motivation: It is often valuable to be able to restrict attention to just those rows of a table that have some desired property. This is commonly done in databases, where the property is satisfaction of a query's constraints.

    Hint: As before, start with an empty table and accumulate the rows that are desired. Be sure to copy those rows that are added so mutation of the new table will not change the current table.

A few test follow, including one in which a predicate selects those rows (only one in the example) with b in the first column.

    t = Table()
    assert t.getData() == []
    t = Table(data=['a,1,2', 'b,3,4'])
    assert t.getData() == [['a', '1', '2'], ['b', '3', '4']]
    tp = t.project([0, 2])
    assert tp.getData() == [['a', '2'], ['b', '4']]
    def rowBpred(row):
        return row[0] == 'b'
    ts = t.select(rowBpred)
    assert ts.getData() == [['b', '3', '4']]

When you are done, submit your final table.py file as a10 using Vincent.