Trouble referencing a series of pre-defined arrays within a loop.

D

Doug_J_W

I have a Visual Basic (2005) project that contains around twenty
embedded text files as resources. The text files contain two columns
of real numbers that are separated by tab deliminator, and are of
different lengths (e.g. usually between 25 and 45 rows. The columns in
each file have the same length). The text files have been numbered
sequentially e.g. cb0, cb1, cb2 and so on. I would like to read the
data from each text file into separate arrays. I am declaring the
arrays so that they are private to the module I am currently working
in. It is important that I do this rather than pass the arrays to
other procedures from my current procedure. This is because many of
the procedures and functions requiring the information in these arrays
are called over 1000000 times in a Monte Carlo simulation. My arrays
have also been named sequentially so that they complement the
filenames e.g. cbArr0, cbArr1, cbArr2 etc.

I can successfully loop through each file and read each of their rows
one by one into a string which is subsequently split into a 1D array.
If I only worry about one file (cb0) I can copy each of the split
values in the 1D array into a dynamic array (cbarr0) that is increased
in size using a loop counter for every line of the file. My problem
occurs when I want to use all my text files and reference the arrays
with a loop counter. I need to create some sort of reference to the
arrays. I have tried various methods that I extracted from a Wrox book
e.g. creating an array list, creating a stack etc. but I can't seem
toget any of them to work. I'm sure there is a very simple solution to
the problem. I am new to vb and inexperienced in a lot of programming
concepts. I can make the code work if I use a case statement but that
is terribly inefficient as it is required for every line of data in
each of the text files. There must be a simpler way that works.

An example of my code that doesn't work is shown below. The code runs
but doesn't work properly. Whilst debugging I can see that the values
from the split string are being stored in the array list and not the
original arrays. They then get over-written by the next line. The re-
dim doesn't seem to change anything.

For clarity 3 files and 3 arrays have been used in the code example.


Option Explicit On
'Option Strict On
Imports System.IO
'Imports System.Collections.Generic

Public Class Form1

Private cbArr0(1, 0), cbArr1(1, 0), cbArr2(1, 0) As Single

Sub generateCB data

'Variable declarations
Dim isoData As String
Dim isoFile As Integer
Dim lineOfData As String
Dim splitLineOfData() As String
Dim lineCount As Integer

'Creates a list allowing code to loop through embedded files
Dim fileList(0 To 1) As String
fileList(0) = My.Resources.cb0
fileList(1) = My.Resources.cb1
fileList(1) = My.Resources.cb2

Dim arrList As New ArrayList
arrList.Add(cbArr0)
arrList.Add(cbArr1)
arrList.Add(cbArr2)

For isoFile = 0 To 2 'Loops through embedded files

isoData = fileList(isoFile) 'reads isochrone file into a
string
Dim string_reader As New StringReader(isoData.ToString)
lineCount = 0

While True
lineOfData = string_reader.ReadLine 'Reads one line of
string at a time
If lineOfData Is Nothing Then
Exit While
Else
splitLineOfData = Split(lineOfData, Chr(9), )
'Splits two columns into 1D array
ReDim Preserve arrList(isoFile)(1, lineCount)
arrList(isoFile)(0, lineCount) =
CSng(splitLineOfData(0))
arrList(isoFile)(1, lineCount) =
CSng(splitLineOfData(1))
lineCount += 1
End If
End While

Next isoFile

End Sub
End Class


Thank you for you time.
DJW
 
B

Branco Medeiros

Doug wrote:
<backposted/>

There are a few problems with your approach (not to mention the
apparent mistypings on lines 20 and 23: Dim fileList(0 To 1) As
String: ... : fileList(1) = My.Resources.cb2 -- those "1"s should be
"2"s, I guess).

The major problem is that you're resorting to ArrayList. An ArrayList
isn't, as its name seems to suggest, a list of arrays. It's a list
that behaves like an array. Don't use it. Ever. It's the reason you
have to disable Option Strict -- always a bad thing to do, when you're
not explicitly using late bind.

In the following lines, copies of your arrays are added to the
ArrayList, not your actual arrays:
arrList.Add(cbArr0)
arrList.Add(cbArr1)
arrList.Add(cbArr2)

Therefore, later, when you do
ReDim Preserve arrList(isoFile)(1, lineCount)

two things happen: First, the code is compiled as late bound code --
VB doesn't know the type of the element in arrList(isoFile), so it
builds less efficient code than what would get compiled if an explicit
array was used. Second, since the array inside arrList is not your
original array, but a copy of it (actually an Object array, not a
Double array), *that* is what get's resized, not your original array.

So, ArrayList is your enemy, don't use it. If you need a dynamic list,
use the generic list instead:

''declares a strongly typed, dynamic list of Double arrays
Dim arrList As New List(Of Double( ) )


Also, if you're concerned with efficiency, don't use a Redim Preserve
inside a loop. Instead, redim the array at one fell swoop *before* the
loop.

Finally, notice that when you Redim an array (preserve or not) VB
creates a new object and assigns it to the array variable. Other
variables will still reference the previous object -- and be out of
synch with the Redim'ed variable.

Without changing your approach too much, this is how your code might
look like:

<aircode>
For isoFile = 0 To 2 'Loops through embedded files
Dim Lines() As String = fileList(isoFile).Split(ControlChars.CrLf)
Dim List(0 To 1, 0 To Lines.Length - 1) As Single

Dim Index As Integer = 0 'resets the line count

For Each LineOfData In Lines
If LineOfData IsNot Nothing Then
splitLineOfData = Split(lineOfData, ControlChars.Tab)
List(0, Index) = CSng(splitLineOfData(0))
List(1, Index) = CSng(splitLineOfData(1))
End If
Index += 1
Next 'LineOfData

Select Case isoFile
Case 0 : cbArr0 = List
Case 1 : cbArr1 = List
Case 2 : cbArr2 = List
'etc, etc, etc
End Select

Next isoFile
</aircode>

HTH.

Regards,

Branco.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top