Formatting rainfall data.
Watch this video to learn about the new concepts shown in the program:
string[,] w = new string[z, y];
In this example, w is declared as a 2D array of z rows and y columns. Columns and rows don’t really exist in the computer’s memory; they are an abstraction that makes the table easier for us to understand. Elements are initialised to null; assign "" to each cell if you want empty strings.
In C#, the multidimensional array shape is fixed when you allocate it. If you don’t know how many rows you’ll need, use List<string[]> (a list of row arrays) and .Add(...) as you read.
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 in advance as shown above. If the number of rows is not known, a List<string[]> 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 list of row arrays
static List<string[]> read_file(string filename)
{
List<string[]> database = new List<string[]>();
StreamReader file = new StreamReader(filename);
string line;
while ((line = file.ReadLine()) != null)
{
string[] fields = line.Trim().Split(',');
database.Add(fields);
}
file.Close();
return database;
}
Questions to think about with this program to check your understanding:
Identify the line where a 2D array is initialised.
The declaration:
string[,] data = new string[num_regions, 2];
Explain what the numbers num_regions and 2 represent in the array declaration.
The number of rows and columns when the two-dimension structure is visualised as a table. Seven rows and two columns.
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] |
Change the program so that it:
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 an array of words separated by a space and using a
foreachloop to iterate and take the first character is the easiest way to solve this problem.
output_short_table that outputs the data in the format shown below.output_short_table subprogram after output_table in the main program.data.txt, which contains:North West,30
North East,31
Central,13
East,10
South East,17
South West,18
Isle of Wight,16
NW | 30
NE | 31
C | 13
E | 10
SE | 17
SW | 18
IoW | 16
read_data
// Read the data from the file into a 2D array
static string[,] read_data(string filename)
{
---
int num_regions = 7;
string[,] data = new string[num_regions, 2];
StreamReader file = new StreamReader(filename);
---
// Read each line of data from the file
for (int region = 0; region < num_regions; region++)
{
---
string data_row = file.ReadLine();
data_row = data_row.Trim();
// Split the row of data by the comma separator into fields
string[] 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
static string padded_label(string label, int characters)
{
---
return label + new string(' ', characters - label.Length);
---
}
---
// Output the table of data
static void output_table(string[,] data)
{
---
int num_regions = 7;
int characters = 0;
---
for (int region = 0; region < num_regions; region++)
{
---
if (data[region, 0].Length > characters)
{
---
characters = data[region, 0].Length;
---
}
---
}
---
for (int region = 0; region < num_regions; region++)
{
---
string table_row = padded_label(data[region, 0], characters);
table_row += " | " + data[region, 1];
Console.WriteLine(table_row);
---
}
---
Console.WriteLine();
}
short_label
// Convert the name of a region into initials
static string short_label(string label)
{
---
// Split label by spaces into a list
string[] region_label_list = label.Split(' ');
string region_label = "";
---
// Take the first letter from each item in the list
foreach (string word in region_label_list)
{
---
region_label += word[0];
---
}
---
return region_label;
}
output_short_table
// Output the table of data with short region names
static void output_short_table(string[,] data)
{
---
int num_regions = 7;
int characters = 0;
---
// Calculate the maximum size of the short region label
for (int region = 0; region < num_regions; region++)
{
---
string region_label = short_label(data[region, 0]);
// Record new maximum
if (region_label.Length > characters)
{
---
characters = region_label.Length;
---
}
---
}
---
// Output the formatted table
for (int region = 0; region < num_regions; region++)
{
---
string region_label = short_label(data[region, 0]);
string table_row = region_label + new string(' ', characters - region_label.Length);
table_row += " | " + data[region, 1];
Console.WriteLine(table_row);
---
}
}