Ask anyone in the software business and you’ll soon learn that
Lesson 12. Working with Two Dimesnional Arrays
In the previous chapter single dimension arrays were covered in depth. In this chapter we extend those same concepts but apply them to a two dimensional array covered in an extended example.
The example we use covers an application being developed by Mary which requires the analysis of heating degree day data supplied to Natural Gas Traders. Mary does not have the actual data so she develops a test data set before she begins her design. She checked the data set shown below with her client and the client agreed that the data is realistic.
Further she was told that the data changed monthly so she decided to display the data in a listbox since the data will be used online.
Oct Nov Dec Jan Feb Mar Apr
NW 1250 1366 1498 1789 1698 1566 0875
NE 1135 1233 1566 1976 2043 1932 1010
SW 0567 0678 1101 1292 1366 1302 0773
SE 0433 0566 1002 1109 1229 1154 0677
The users need to see the raw data shown above but additional data is required as shown in the sample layout they provided.
Regional Natural Gas Consumption
Previous Heating Season
(bil Cu. Ft)
Oct Nov Dec Jan Feb Mar Apr Total High Low Mean Median
NW 1250 1366 1498 1789 1698 1566 0875 xxxx xxxx xxxx xxxx xxxx
NE 1135 1233 1566 1976 2043 1932 1010 xxxx xxxx xxxx xxxx xxxx
SW 0567 0678 1101 1292 1366 1302 0773 xxxx xxxx xxxx xxxx xxxx
SE 0433 0566 1002 1109 1229 1154 0677 xxxx xxxx xxxx xxxx xxxx
--------------------------------------------------------------------------------
Total xxxx xxxx xxxx xxxx xxxx xxxx xxxx G,GGGG
High xxxx xxxx xxxx xxxx xxxx xxxx xxxx HHHH
Low xxxx xxxx xxxx xxxx xxxx xxxx xxxx LLLL
Mean xxxx xxxx xxxx xxxx xxxx xxxx xxxx MEAN
Median xxxx xxxx xxxx xxxx xxxx xxxx xxxx MEDIAN
Essentially the traders want to be able to click an icon and have the above table displayed on their screens.
The row and columnar data in the body of the report is clear, but Mary was confused about the lower right corner of the report. The traders cleared up the confusion by defining the placeholders.
G,GGG The total of the 28 Heating Degree Day(HDD)Values.
HHHH The High of all Highs
LLLL The Low of all Lows
MEAN The mean of the 28 raw data values
MEDIAN The median of the 28 raw data values
Since this application seems somewhat more difficult than the application in the previous chapter, we suggest a divide and conquer approach.
So listing tasks and any issues that arise seems to be a good first step. The following is a reasonable list.
Task 1 Initialize variables.
Task 2 Get the raw data from the file and validate the data by dropping it into a listbox.
Task 3 Revise Task 2 by converting the text data into numeric format and display it in a listbox or send it to Debug.WriteLine. (This assures we get the variables of interest.)
Task 4. Revise 3 so that we get the data into into a 2D array.
Task 5. Compute the statistics.
Task 6. Build and display the data in the listbox.
Clearly this application has a number of distinct steps, so Mary immediately decides to build a small collection of methods that would be called from within the form load event. The application does seem quite clear so she decides to immediately write code instead of building PDL first. As far as application documentation, she will let the documentation be the code !
Task 2 Get the raw data from the file and validate the data by dropping it into a listbox. With nothing new, the code in Fig 1. below accomplishes this task. But the data is simply string data and certainly not in the desired array. After execution the list box does contain the data as shown in Figure 2.
Imports System.IO
Public Class frmMain
Dim H1, H2, H3, H4 As String
Private Sub frmMain_Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles MyBase.Load
GetHeatingDegreeDayData()
End Sub
Sub GetHeatingDegreeDayData()
Dim sInputFilePath As String = "c:\HDD.txt"
Dim fileIn As New StreamReader(sInputFilePath)
Dim sRecIn As String
' Get the Heading line from the File
sRecIn = fileIn.ReadLine()
H4 = sRecIn
' Get the detail records from the file
Do Until sRecIn Is Nothing
ListBox.Items.Add(sRecIn)
sRecIn = fileIn.ReadLine()
Loop
End Sub
Figure 1. Task 1 code
[pic]
Figure 2. The raw data in the original string format.
Well, that certainly looks promising, but Mary needs to capture the 28 numeric values from the string data. Once she can grab each value, she needs to drop it into the array. First she needs to define the array thus giving it a size. Nine rows by 12 columns seems reasonable to hold the numeric data. This should make sense after you reexamine the report format shown above.
Ater spending about a six hours Mary arrives at the following code segment that works as expected.
Sub GetHeatingDegreeDayData()
Dim sInputFilePath As String = "c:\HDD.txt"
Dim fileIn As New StreamReader(sInputFilePath)
Dim sRecIn As String
Dim i, j As Byte ' array indexers
Dim HDD(9, 12) As Single ' since we want 1 decimal position accuracy
' in the averages.
' Get the Heading line from the File
sRecIn = fileIn.ReadLine()
H4 = sRecIn
sRecIn = fileIn.ReadLine()
Dim sOut As String = Nothing ' use sOut to build a string to display
For i = 0 To 3 ‘ because we have three lines of numeric data
HDD(i, 0) = CSng(Mid$(sRecIn, 5, 4))
HDD(i, 1) = CSng(Mid$(sRecIn, 13, 4))
HDD(i, 2) = CSng(Mid$(sRecIn, 19, 4))
HDD(i, 3) = CSng(Mid$(sRecIn, 26, 4))
HDD(i, 4) = CSng(Mid$(sRecIn, 33, 4))
HDD(i, 5) = CSng(Mid$(sRecIn, 40, 4))
HDD(i, 6) = CSng(Mid$(sRecIn, 47, 4))
‘ SetUp sOut so we can display it.
For j = 0 To 6 : sOut += CStr(HDD(i, j)) + " " : Next
Debug.WriteLine(sOut)
sOut = Nothing ' Reset sOut
sRecIn = fileIn.ReadLine() ' Get the next line of text
Next i
End Sub
Her code is straightforward but a little bulky in that she doesn’t use a loop to grab the 7 data values in each line. When the data are not equally spaced an inner loop will not work. The good news is that she has the data in the HDD array! As she reviews her code she realizes that the HDD array is defined within the GetHeatingDegreeDayData method. This appears problematic since HDD will also be used in the statistics method. So she decides to change it from being local to being Global. To do this she cuts these lines
Dim HDD(9, 12) As Single ' since we want 1 decimal position accuracy
' in the averages.
Dim i, j As Byte ' array indexers
out of the GetHeatingDegreeDayData method and pastes them after the
Dim H1, H2, H3, H4 As String statement thus making these variable global.
Now the HDD array can be manipulated by any of the routines in the Class.
This completes Task 4.
Task 5 requires getting the statistics and placing them in the appropriate cells of the HDD array. The first thing Mary does is begins to plan how she will attack the statistics. The totals for the rows and columns seem to be straightforward and she thinks that as she makes those passes through the row and column data, she might as well find the row and column high and low values. Finally getting the averages shouldn’t be that difficult. That should be enough to work on for now, so she postpones handling the summarial totals in the bottom right corner of the report as well as the medians. In fact, she decides to get the row statistics first. Below is her first pass at the output which she immediately checks with a calculator.
1250 1366 1498 1789 1698 1566 875
1135 1233 1566 1976 2043 1932 1010
567 678 1101 1292 1366 1302 773
433 566 1002 1109 1229 1154 677
1250 1366 1498 1789 1698 1566 875
1135 1233 1566 1976 2043 1932 1010
567 678 1101 1292 1366 1302 773
433 566 1002 1109 1229 1154 677
============= Row Statistics Follow ===========
Total High Low Mean
10042 1789 875 1434.571
10895 2043 1010 1556.429
7079 1366 567 1011.286
6170 1229 433 881.4286
The row statistics are correct and her code is shown on the next page.
Imports System.IO
Public Class frmMain
Dim H1, H2, H3, H4 As String
Dim HDD(9, 12) As Single ' since we want 1 decimal position accuracy
' in the averages.
Dim i, j As Byte ' array indexers
Dim sOut As String = Nothing ' use sOut to build a string to display data
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
GetHeatingDegreeDayData()
GetTotalsAverageHighLow()
End Sub
Sub GetHeatingDegreeDayData()
Dim sInputFilePath As String = "c:\HDD.txt"
Dim fileIn As New StreamReader(sInputFilePath)
Dim sRecIn As String
sRecIn = fileIn.ReadLine() ' Get the Heading line from the File
H4 = sRecIn
sRecIn = fileIn.ReadLine()
For i = 0 To 3
HDD(i, 0) = CSng(Mid$(sRecIn, 5, 4))
HDD(i, 1) = CSng(Mid$(sRecIn, 13, 4))
HDD(i, 2) = CSng(Mid$(sRecIn, 19, 4))
HDD(i, 3) = CSng(Mid$(sRecIn, 26, 4))
HDD(i, 4) = CSng(Mid$(sRecIn, 33, 4))
HDD(i, 5) = CSng(Mid$(sRecIn, 40, 4))
HDD(i, 6) = CSng(Mid$(sRecIn, 47, 4))
For j = 0 To 6 : sOut += CStr(HDD(i, j)) + " " : Next
Debug.WriteLine(sOut)
sOut = Nothing ' Reset sOut
sRecIn = fileIn.ReadLine() ' Get the next line of text
Next i
End Sub
Sub GetTotalsAverageHighLow()
' Iterate over columns to get the row statistics.
Dim MONTHS = 7
For i = 0 To 3
HDD(i, 8) = Single.MinValue ' Initialize High
HDD(i, 9) = Single.MaxValue ' Initialize Low
For j = 0 To 6
HDD(i, 7) += HDD(i, j) ' Build the Total Column.
If HDD(i, j) > HDD(i, 8) Then HDD(i, 8) = HDD(i, j) 'Get High
If HDD(i, j) < HDD(i, 9) Then HDD(i, 9) = HDD(i, j) 'Get Low
Next j
HDD(i, 10) = HDD(i, 7) / MONTHS
Next i
' Let's temporarily display the data
Debug.WriteLine("============= Row Statistics Follow ===========")
Debug.WriteLine(" Total High Low Mean ")
For i = 0 To 3
sOut = CStr(HDD(i, 7)) + " " _
+ CStr(HDD(i, 8)) + " " _
+ CStr(HDD(i, 9)) + " " _
+ CStr(HDD(i, 10))
Debug.WriteLine(sOut)
Next i
End Sub
End Class
Well, given she has all of the code for the row statistics, she copies and pastes this code below the row statistics code and revises it to handle the columnar totals.
The new output is shown below.
1250 1366 1498 1789 1698 1566 875
1135 1233 1566 1976 2043 1932 1010
567 678 1101 1292 1366 1302 773
433 566 1002 1109 1229 1154 677
============= Row Statistics Follow ===========
Total High Low Mean
10042 1789 875 1434.571
10895 2043 1010 1556.429
7079 1366 567 1011.286
6170 1229 433 881.4286
============= Column Statistics Follow ===========
Rows below show Total,High,Low, Mean values
3385 3843 5167 6166 6336 5954 3335
1250 1366 1566 1976 2043 1932 1010
433 566 1002 1109 1229 1154 677
846.25 960.75 1291.75 1541.5 1584 1488.5 833.75
=====================================================
Again, Mary checks the data and it is correct.
Below is the code block that she added after the row statistics code.
'===================================================================
'=========================================== Get Columnar Statistics
'===================================================================
Dim REGIONS As Byte = 4
sOut = Nothing
For j = 0 To 6
HDD(5, j) = Single.MinValue ' Initialize High
HDD(6, j) = Single.MaxValue ' Initialize Low
For i = 0 To 3
HDD(4, j) += HDD(i, j) ' Build the Total Column.
If HDD(i, j) > HDD(5, j) Then HDD(5, j) = HDD(i, j) 'Get High
If HDD(i, j) < HDD(6, j) Then HDD(6, j) = HDD(i, j) 'Get Low
Next i
HDD(7, j) = HDD(4, j) / REGIONS
Next j
' Let's temporarily display the data
Debug.WriteLine("============= Column Statistics Follow ===========")
Debug.WriteLine(" Rows below show Total,High,Low, Mean values")
For i = 4 To 7
For j = 0 To 6
sOut += CStr(HDD(i, j)) + " "
Next j
Debug.WriteLine(sOut)
sOut = Nothing
Next i
Debug.WriteLine("=====================================================")
' ============================================ End Columnar Statistics
End Sub
Next, she turns her attention to the statistics in the lower right corner of the report, namely the G,GGG HHHH, LLLL, MEAN, MEDIAN values. Each of these values fall within a cell of the HDD array. Rather than making the GetTotalsAverageHighLow() too large, she adds another method called GetOverAllStatistics() which will get the first four of the five values she needs for the lower right section of the report.
She realizes that these statistics pertain to all 28 data points. Two ways of obtaining the statistics are possible. Obtain the Low of the already computed lows, then the Highs of the already computed Highs and the average of the averages ( which isn’t quite correct and if you don’t believe it try it!) Another method is to look at the 28 values and simply compute the High, Low, and Average using the raw data that is already in the array. This is the method she chooses.
Before continuing, she decides to display all of the data in the array – 9 rows by 12 columns just to be sure all is well. She saw what she expected and then computed the overall statistics. Using the code she has already written to high, low, mean value she now iterates over all 28 values in order to generate the summarial statistics. That code is shown below.
Sub GetOverAllStatistics()
Dim HDD_OBSERVATIONS As Byte = 28
HDD(5, 8) = Single.MinValue ' Initialize Highest Value
HDD(6, 9) = Single.MaxValue ' Initialize Lowest Value
For i = 0 To 3
For j = 0 To 6
HDD(4, 7) += HDD(i, j)
If HDD(i, j) > HDD(5, 8) Then HDD(5, 8) = HDD(i, j)
If HDD(i, j) < HDD(6, 9) Then HDD(6, 9) = HDD(i, j)
Next j
Next i
HDD(7, 10) = HDD(4, 7) / HDD_OBSERVATIONS ‘ Get Overall Average
Debug.WriteLine("------------------- Full Array Listing -------------")
For i = 0 To 8
sOut = Nothing
For j = 0 To 11
sOut += CStr(HDD(i, j)) + " "
Next
Debug.WriteLine(sOut)
Next
Debug.WriteLine("------------------------------------------------------")
End Sub
Task 5 is taking quite a while to complete, but finally she reaches the last step in this task – Get the Medians ! To keep the code nicely organized she adds a GetMedians method. She know that to compute the grand median ( the value in the lower right corner of the report, she needs to get all 28 values into a single dimension array inorder to sort. Then once thay are sorted, she will take the average the center two values to obtain the grand median since we have an even number of values. Remember that the median is that value that has as many values on the left as it has on the right.
Mary wrote the code below to compute the Grand Median. Frm_Load was revised as shown.
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
GetHeatingDegreeDayData()
GetTotalsAverageHighLow()
GetOverAllStatistics()
GetTheMedians()
End Sub
And the first part GetTheMedians() code follows.
Sub GetTheMedians()
Dim Hold(28) As Single
Dim n As Byte
' -------- Copy 28 values into Hold and find the Grand Median
For i = 0 To 3
For j = 0 To 6
Hold(n) = HDD(i, j)
n += 1
Next j
Next i
Array.Sort(Hold)
HDD(8, 11) = (Hold(14) + Hold(15)) / 2
‘ --------------------------- Now lets show the data
Debug.WriteLine("------------------- Full Array Listing -------------")
For i = 0 To 8
sOut = Nothing
For j = 0 To 11
sOut += CStr(HDD(i, j)) + " "
Next
Debug.WriteLine(sOut)
Next
Debug.WriteLine("------------------------------------------------------")
End Sub
Next Mary needed to figure out how to get the medians for each of the data rows and columns and place the medians in row 8 ( ie the months) and column 11( ie the regions).
The regions had seven data items per row and the months had four data items per column. Also, the client sent her another sample data set that they suggested she use.
She decided to build another routine to handle the medians and call it from the frmMain_Load event. The code for the median routine follows. As usual we suggest that you copy the code line for line so that you see the meaning of each line. We find that simply reading the code isn’t as effective as copying it with a pencil and paper. We also suggest that you reverse engineer the actual code back into PDL . Do this on another sheet of paper.
Sub GetTheMedians()
Dim Hold(28) As Single
Dim n As Byte
' -------- Copy 28 values into Hold and find the Grand Median
For i = 0 To 3
For j = 0 To 6
Hold(n) = HDD(i, j)
n += 1
Next j
Next i
Array.Sort(Hold)
HDD(8, 11) = (Hold(14) + Hold(15)) / 2
'----------------------------------------------------------------------
' Get the Four Row Medians
'----------------------------------------------------------------------
Dim Hold2(7) As Single
For i = 0 To 3
For n = 0 To 6 : Hold2(n) = 0 : Next n ' Initialize Hold
For j = 0 To 6 : Hold2(j) = HDD(i, j) : Next ' Fill Hold2
Array.Sort(Hold2)
HDD(i, 11) = Hold2(4)
Next i
'----------------------------------------------------------------------
' Get the Seven Column Medians
'----------------------------------------------------------------------
Dim Hold3(4) As Single
Debug.WriteLine("=================== In Medians ===============")
For j = 0 To 6
For i = 0 To 3 : Hold3(i) = 0 : Next i ' Initialize Hold
For i = 0 To 3 : Hold3(i) = HDD(i, j) : Next ' Fill Hold3
'Debug.WriteLine("===========================================")
'sOut = Nothing
'sOut = "===" + CStr(Hold3(0)) + " " + CStr(Hold3(1)) _
' + " " + CStr(Hold3(2)) + " " + CStr(Hold3(3))
'Debug.WriteLine(sOut)
'Array.Sort(Hold3)
'sOut = Nothing
'sOut = "===" + CStr(Hold3(0)) + " " + CStr(Hold3(1)) _
' + " " + CStr(Hold3(2)) + " " + CStr(Hold3(3))
'Debug.WriteLine(sOut)
'Debug.WriteLine("===========================================")
HDD(8, j) = (Hold3(1) + Hold3(2)) / 2
Next j
End Sub
Mary tested the above code to be sure the medians were correct and after a few trial and error attempts the code was correct.
Finally it was time for the last Task – Display the report. This last task proved problematic. She was using which did not have Report Writing features built in. But she thought she would give it a try and at least get all of the data on paper. Below is the code she wote to generate the report.
Sub DisplayReport()
Dim H1, H2, H3, H4 As String
Dim RowTitle(9) As String
RowTitle(0) = "NW "
RowTitle(1) = "NE "
RowTitle(2) = "SW "
RowTitle(3) = "SE "
RowTitle(4) = "Total "
RowTitle(5) = "High "
RowTitle(6) = "Low "
RowTitle(7) = "Mean "
RowTitle(8) = "Median "
H1 = " Regional Natural Gas Consumption"
H2 = " Previous Heating Season"
H3 = " ( bil Cu. Ft. )"
H4 = " Oct Nov Dec Jan Feb Mar Apr _
Total High Low Mean Median"
Debug.WriteLine(H1)
Debug.WriteLine(H2)
Debug.WriteLine(H3)
Debug.WriteLine(H4)
For i = 0 To 3
sOut = RowTitle(i)
For j = 0 To 11
' sOut += CStr(HDD(i, j)) + " "
sOut += FormatNumber(HDD(i, j), 0) + " | "
Next
Debug.WriteLine(sOut)
Next
Debug.WriteLine("------------------------------------------------------_
-----------------------------------------------")
For i = 4 To 8
sOut = RowTitle(i)
For j = 0 To 11
If HDD(i, j) = 0 Then
sOut += " | "
Else
sOut += FormatNumber(HDD(i, j), 0) + " | "
End If
Next
Debug.WriteLine(sOut)
Next
End Sub
The output for the above method is shown below. The revised data set is shown above the actual report output.
[pic]
She did a little research and found that GDI+ could be used to help build a more nicely formatted report, but it would be a time consuming process. Buying a more powerful version of was suggested and rejected. She then remembered a concept covered in an early course she took. The idea was that you could generate data and send it to a text file and then import the text file into Excel and use the power of Excel to format the data.
She also knew her clients were heavy Excel users. The code below was inserted.
‘ ================================ Send the output to the Immediate Window
For i = 4 To 8
sOut = RowTitle(i)
For j = 0 To 11
If HDD(i, j) = 0 Then
sOut += " | "
Else
sOut += FormatNumber(HDD(i, j), 0) + " | "
End If
Next
Debug.WriteLine(sOut)
Next
'===========================================================================
' Send the data to a text file
'===========================================================================
Dim sOutputFilePath As String = "c:\HDDReport1.txt"
Dim fileOut As New StreamWriter(sOutputFilePath)
Dim sRecOut As String = Nothing
For i = 0 To 8
For j = 0 To 11
sRecOut += CStr(HDD(i, j)) + ","
Next j
fileOut.WriteLine(sRecOut)
sRecOut = Nothing
Next i
fileOut.Close()
End Sub
The Excel Output is shown below.
[pic]
Mary was surprised at the amount of work it took to generate such a report but considered the effort to be a meaningful learning experience. She learned how to break a multitask project into smaller tasks and then expanded those tasks into code.
You might think that she should have started in Excel immediately, but the purpose of this exercise was of course to cover working with two dimensional arrays from within a programming language.
As an extended exercise, we suggest that you copy Mary’s code character by character using a pencil and paper, key it yourself and run it. In addition Extracting the PDL from the code is another beneficial exercise. Remember that in the real world first the PDL would be developed and validated before any code was written. Depending on the needs of the client, sometimes the PDL step might be omitted.
................
................
In order to avoid copyright disputes, this page is only a partial summary.
To fulfill the demand for quickly locating and searching documents.
It is intelligent file search solution for home and business.
Related searches
- fill in the blank business plan
- fill in the blank business plan pdf
- ask and you will receive scripture
- learn continuously in the workplace
- ask and you shall receive bible verse
- if you ask anything in my name
- ask and you shall receive scripture
- polio epidemic in the 1940 s and 1950 s
- scripture ask and you shall receive
- ask and you will receive
- barnes and noble coming soon books
- ask and you shall receive