Formatting rainfall data.

Rainfall collector

Try

Watch this video to learn about the new concepts shown in the program:

Knowledge organiser

w = [[x for columns in range(y)] for rows in range(z)]

In this example, w is declared as a 2D array of y columns and z rows with each element assigned to be x.

x could be a number or a string. Typically to create an empty table, x would be the empty string “”.

Although columns and rows are used as variables to make the code easy to read, this is an abstraction. How you visualise the table is up to you.

You could define a 2D list where the number of elements is unknown and can change, but you cannot refer to a specific index until it contains data.

Data can be stored in comma separated file (CSV) format, where each row (record) has data separated into columns (fields) by commas.

If the number of rows and columns is known, you can use a 2D array initialised with two for loops as shown above. If the number of rows is not known, a 2D list will be needed with new rows added to the list as they are read from the file.

This is a common operation when using files and 2D lists. Here is some boilerplate code that can be used to read data from a file and return it in a 2D list called database.

# Read data from filename and return a 2D list
def read_file(filename):
    database = []
    file = open(filename, "r")
    # Read each line of data until end of file
    for record in file:
        record = record.strip()
        fields = record.split(",")
        database.append(fields)
    file.close()
    return database

Investigate

Questions to think about with this program to check your understanding:

Item question

Identify the line where a 2D array is initialised.

Reveal answer

Line 8:

data = [["" for columns in range(2)] for rows in range(num_regions)]
Structure question

Explain what the numbers 2 and 7 represent in the code in line 8.

Reveal answer

The number of rows and columns when the two-dimension structure is visualised as a table. Two columns and seven rows.

As the structure is zero-indexed, the first index is 0, so the indexes for seven rows are 0-6, and the columns 0-1.

Index 0 1
0 data[0][0] data[0][1]
1 data[1][0] data[1][1]
2 data[2][0] data[2][1]
3 data[3][0] data[3][1]
4 data[4][0] data[4][1]
5 data[5][0] data[5][1]
6 data[6][0] data[6][1]

Make

Change the program so that it:

  1. Includes a function called short_label that takes a parameter label and returns the first character from each word in label. E.g. South West would be SW.

    Hint

    Splitting the label into a list of words separated by a space and using a for loop to iterate the list extracting the first character is the easiest way to solve this problem.

  2. Includes a subprogram called, output_short_table that outputs the data in the format shown below.
  3. Calls the output_short_table subprogram after output_table in the main program.

Typical inputs and outputs from the program would be:

NW  | 30
NE  | 31
C   | 13
E   | 10
SE  | 17
SW  | 18
IoW | 16

Restricted automated feedback

Automated feedback for this assignment is still under construction. Submitted programs are checked for syntax errors and their source code is checked for potential errors, bugs, stylistic issues, and suspicious constructs. However, no checks are performed yet to see if the program correctly implements the behaviour specified in the assignment.

🆘 If you're really stuck, use this Parsons code sorting exercise
read_data
# Read the data from the file into a 2D array
def read_data(filename):
---
    num_regions = 7
    data = [["" for columns in range(2)] for rows in range(num_regions)]
    file = open(filename, "r")
---
    # Read each line of data from the file
    for region in range(num_regions):
---
        data_row = file.readline()
---
        data_row = data_row.strip()
---
        # Split the row of data by the comma separator into fields
        data_list = data_row.split(",")
---
        # Populate the data table with the fields
        data[region][0] = data_list[0]
        data[region][1] = data_list[1]
---
    file.close()
---
    return data
padded_label, output_table
# Pad data with spaces to achieve a chars string length
def padded_label(label, characters):
    return label + " " * (characters - len(label))
---

# Output the table of data
def output_table(data):
---
    num_regions = 7
    characters = 0
---
    for region in range(num_regions):
---
        if len(data[region][0]) > characters:
---
            characters = len(data[region][0])
---
    for region in range(num_regions):
---
        table_row = padded_label(data[region][0], characters)
---
        table_row = table_row + " | "
---
        table_row = table_row + data[region][1]
---
        print(table_row)
---
    print()
short_label
# Convert the name of a region into initials
def short_label(label):
---
    # Split label by spaces into a list
---
    region_label_list = label.split(" ")
    region_label = ""
---
    # Take the first letter from each item in the list
    for word in region_label_list:
---
        region_label = region_label + word[0]
---
    return region_label
read_data
# Output the table of data with short region names
def output_short_table(data):
---
    num_regions = 7
    characters = 0
---
    # Calculate the maximum size of the region data label
    for region in range(num_regions):
---
        region_label = short_label(data[region][0])
---
        # Record new maximum
        if len(region_label) > characters:
---
            characters = len(region_label)
---
    # Output the formatted table
    for region in range(num_regions):
---
        region_label = short_label(data[region][0])
---
        table_row = region_label
---
        table_row = table_row + " " * (characters - len(region_label))
---
        table_row = table_row + " | "
---
        table_row = table_row + data[region][1]
---
        print(table_row)