...help arraylists to string

Status
Not open for further replies.

Nemesis09

Active member
Joined
Jul 25, 2006
Messages
31
Location
NSW, Australia
Programming Experience
Beginner
...help arraylist to array

Hi all,

This is my first post (probably of many) on this site, basically, I'm half ok at VB6 after playing with it as a hobby for a few years, and I figured it was about time I switched to .NET

Thats where all my problems began...

Ok, the one of most concern at the moment is this:

I'm trying to write an app that reads data from 2 comma separated text files, and puts these into a single 2 dimentional array basd on one of the culumns of data, such as.

VB.NET:
Text File 1:
0001, data
0002, test
0003, other
0032, something
 
Text File 2:
0001, Fred
0002, John
0003, Sam
0032, Bert
 
Array:
0001, Fred, data
0002, John, test
0003, Sam, other
0032, Bert, something
Now, this seems like a simple enough task... but it just wont work. Heres my code as it stands (after more attempts than I can remember).

VB.NET:
Dim employees(,)
Dim apppath AsString
Dim times(1, 3) AsString
 
Private Sub Form_load
 
apppath = Windows.Forms.Application.StartupPath
Dim arraylst AsNew ArrayList
Dim reader As Microsoft.VisualBasic.FileIO.TextFieldParser
reader = My.Computer.FileSystem.OpenTextFieldParser(apppath & "\employees.dat")
reader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
reader.SetDelimiters(",")
WhileNot reader.EndOfData
Try
arraylst.Add(reader.ReadFields)
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & "is not valid and will be skipped.")
EndTry
EndWhile
Dim employees As Array = arraylst.ToArray
 
Private Sub Button_1
 
Dim arraylst AsNew ArrayList
Dim reader As Microsoft.VisualBasic.FileIO.TextFieldParser
reader = My.Computer.FileSystem.OpenTextFieldParser(apppath & "\loggings.dat")
reader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
reader.SetDelimiters(",")
WhileNot reader.EndOfData
Try
arraylst.Add(reader.ReadFields)
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message & "is not valid and will be skipped.")
EndTry
EndWhile
Dim times As Array = arraylst.ToArray

This seems to be getting close, but throws an error because apparently you cant convert a "String() to a String" ...um... why? whats the difference and whats the use of this "String()" type. I cant seem to do anything with it, not even set a label.text to it for debugging.

So I guess I'm asking, how do I get these arraylists into a type that I can actually use (ie. String)

Thanks for any and all help or suggestions (I'm still open to scrapping all this code and going for a different approach if there's a better way)
 
Last edited:

skaryChinezeGuie

Well-known member
Joined
Apr 23, 2006
Messages
94
Programming Experience
Beginner
I'm not that smart but tags will help your posts be more readable.
code and /code with []'s around them
 

cjard

Well-known member
Joined
Apr 25, 2006
Messages
7,052
Programming Experience
10+
Nemesis09 said:
Hi all,
Dim reader As Microsoft.VisualBasic.FileIO.TextFieldParser




euwww... Microsoft.VisualBasic stuff! euww :)
I found a great CSV file reader as part of a free suite of tools called JHL_Tools.dll - you can google for it and read more about it.. Anyways, excepting that aside, lets take a look at what's going wrong.

You know how to use the debugger, right? When your program encounters an error etc. For easier debugging you can set the debugger to halt as soon as an exception is thrown. You can also set breakpoints or single step. Do you know how to do these?

(Click Debug... Exceptions and tick the boxes in the THROWN column. now a break will occur when an exception is thrown not jsut when there is no catch for it)
(CLick the line number or leftmost edge of the code window (to the left of the editable column 0) to drop a breakpoint. Execution stops when it reaches this line)
(Single step with F8, step over method calls with Shift-F8)

So find our where your error is ocurring..



Now, you need to get more used to data types and things.. A string and an array of Strings are not the same. Just like you wouldnt say that a Car and a carpark full of Cars are the same, String and String() are different.

Why cant you use an arraylist? What does reader.ReadFields return?
Are you aware of what an arraylist is for and how it works?


I havent actually solved your problem here because I dont know what line is causing the error (you havent told me) - you need to use the debugger or soemthing, and find out.

I think youre going to have to throw away a lot of VB6 knowledge and start with a good book on .NET - at the risk of sounding rude, I dont think you were using arrays properly in VB6 to start with and your knowledge/understanding of strongly types languages needs supplementing.. I could teach it, but it's a little beyond the scope of the forum. I'm sure someone will recommend a book though.. and it doesnt even have to be on VB.net - i came to it through knowledeg of VB6 keywords and syntax, but with an OO grounding in java and c#. You could read a book on either of these languages and apply the understanding of strong typing and OO principles to your VB coding.. It _is_ a bit of a leap though (the jump from so-so procedural VB6 to OO .NET) so be prepared to do quite a bit of thinking :)
 
Last edited:

Nemesis09

Active member
Joined
Jul 25, 2006
Messages
31
Location
NSW, Australia
Programming Experience
Beginner
Ok...
I do know that an array of strings is not the same as a string, as you say. I just didn't know that String() represented an array of strings (although the format "array()" makes that painfully obvious now.

The actual error is that a "String() cant be converted to a String" which is understandable after being told what a String() is. However, if x is a variable of type "String()" then would that mean "x(y)" would be a String? Or is an "Array of Strings, ie. of variable of type String()" different to a single dimentional array of type String?

I mean, is:

VB.NET:
Dim var As String()

the same as:

VB.NET:
Dim var() As String


And therefore shouldn't a single dimentional array of String()'s be a multidimentional array of Strings?

And what makes you say I probably wasent using arrays correctly in VB6? I never had any trouble... I would have been able to use a combination of Split and ReDim to get this done... but I hear thats not the way its done anymore, and if I'm going to use VB.NET I may as well do it right.

Thanks for any further info.
 

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,517
Location
Norway
Programming Experience
10+
cjard said:
euwww... Microsoft.VisualBasic stuff! euww
Are you sick or something?? Stay home until you're not contagious anymore then.

What Nemesis09 posted is the preferred way to read delimited text files with Visual Basic 2005/.Net 2.0, it also equivalent of using the magnificent new My feature to navigate My.Computer.FileSystem.OpenTextFieldParser. This is also what you get when you use the new "Insert Snippet" feature (Edit, Intellisense, Insert Snippet - or use context menu in code view). "Reading from Files in Visual Basic" http://msdn2.microsoft.com/en-us/library/wz100x8w.aspx

Nemesis09, your code breaks on Form_Load line 'arraylst.Add(reader.ReadFields)'. When you check documentation you'll see that the ReadFields method returns an array of strings and that the ArrayList.Add method adds an object to the end of the list of items. You don't want to add an array as a new item in your ArrayList, you want to add the items in the array. Use the AddRange to add a range of objects. 'arraylst.AddRange(reader.ReadFields)' will be fine. The technical explanation of why this is possible with an array you can read in documentation.

And there is no difference in a string array and an array of strings as you asked. Also, String and String() are the same, they are both data types, but objects of each will be different type objects.

The reason both convensions exist is because of the different contexts you have to use one or the other. For instance when declaring an array with an initial number of elements you can't say 'Dim x As String(10)', you get an error 'array bound cannot appear in type specifiers'. You have to do 'Dim x(10) As String'. String is a type and String() is a type but String(10) is not a type. For a function methods return type (! type :)) to return an array the function type must be String(), there is no way of tucking those () array qualifiers anywhere else in that case. Example 'Public Function returnsstringarray() As String()' (Yes, we see people that set the function return type to String, then they declare an array of strings and try to return this object. No Go.)

Your last question: shouldn't a single dimentional array of String()'s be a multidimentional array of Strings?
If you try to do this 'Dim x(10) As String()' you'll get an error saying 'array modifiers cannot be specified on both the variable and its type'. So there you have it, a case where type String() cannot be used.
 

Nemesis09

Active member
Joined
Jul 25, 2006
Messages
31
Location
NSW, Australia
Programming Experience
Beginner
...now were getting somewhere

Ok, so with this new information that a String() is infact an array of strings, and not a single value, I've redone my code and all I've done so far works perfectly.

This the new code:

VB.NET:
[SIZE=2][COLOR=#0000ff]Public[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Class[/COLOR][/SIZE][SIZE=2] Form1
[/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] apppath [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]String
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] times(,) [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]String
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] employees(,) [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]String[/COLOR][/SIZE]
 
[SIZE=2][COLOR=#0000ff]
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Private[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Sub[/COLOR][/SIZE][SIZE=2] Button1_Click[/SIZE][SIZE=2]
[/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] arraylst [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]New[/COLOR][/SIZE][SIZE=2] ArrayList
[/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] tempread [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]String[/COLOR][/SIZE][SIZE=2]()
[/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] templine(3) [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]String
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] reader [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] Microsoft.VisualBasic.FileIO.TextFieldParser
reader = [/SIZE][SIZE=2][COLOR=#0000ff]My[/COLOR][/SIZE][SIZE=2].Computer.FileSystem.OpenTextFieldParser(apppath & [/SIZE][SIZE=2][COLOR=#800000]"\loggings.dat"[/COLOR][/SIZE][SIZE=2])
reader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
reader.SetDelimiters([/SIZE][SIZE=2][COLOR=#800000]","[/COLOR][/SIZE][SIZE=2])
[/SIZE][SIZE=2][COLOR=#0000ff]While[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Not[/COLOR][/SIZE][SIZE=2] reader.EndOfData
[/SIZE][SIZE=2][COLOR=#0000ff]Try
[/COLOR][/SIZE][SIZE=2]tempread = reader.ReadFields
templine(0) = tempread(2)
templine(1) = tempread(3)
templine(2) = tempread(4)
arraylst.Add(templine)
[/SIZE][SIZE=2][COLOR=#0000ff]Catch[/COLOR][/SIZE][SIZE=2] ex [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2] Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox([/SIZE][SIZE=2][COLOR=#800000]"Line "[/COLOR][/SIZE][SIZE=2] & ex.Message & [/SIZE][SIZE=2][COLOR=#800000]"is not valid and will be skipped."[/COLOR][/SIZE][SIZE=2])
[/SIZE][SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Try
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]End[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]While
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] x [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Integer
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Dim[/COLOR][/SIZE][SIZE=2] y [/SIZE][SIZE=2][COLOR=#0000ff]As[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]Integer
[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]ReDim[/COLOR][/SIZE][SIZE=2] times(2, arraylst.Count)
[/SIZE][SIZE=2][COLOR=#0000ff]For[/COLOR][/SIZE][SIZE=2] x = 0 [/SIZE][SIZE=2][COLOR=#0000ff]To[/COLOR][/SIZE][SIZE=2] 2
[/SIZE][SIZE=2][COLOR=#0000ff]For[/COLOR][/SIZE][SIZE=2] y = 0 [/SIZE][SIZE=2][COLOR=#0000ff]To[/COLOR][/SIZE][SIZE=2] (arraylst.Count - 1)
times(x, y) = arraylst(x)(y)
[/SIZE][SIZE=2][COLOR=#0000ff]Next[/COLOR][/SIZE][SIZE=2] y
[/SIZE][SIZE=2][COLOR=#0000ff]Next[/COLOR][/SIZE][SIZE=2] x[/SIZE]
End Sub

And the same for the other file, now I have the values I need from both files stored in two arrays, thats something I can work with. :)

JohnH:
Thanks for sticking up for the new guy :)
Yeah, after being told that a String() was infact an "Array of Strings" I definatley understand the point of this data type and even made use of it in the new version of my code. I can't believe I didn't figure it out by the "()" after it...

I also think the addrange method you suggested is exactly what I was looking for, although the method I used works and gives me good control over which Strings out of the .ReadFields String() are put in the arraylist, not that there wouldn't be a way to do it using your method I assume. Thanks heaps for the info.
 
Last edited:

cjard

Well-known member
Joined
Apr 25, 2006
Messages
7,052
Programming Experience
10+
JohnH said:
Are you sick or something??
Totally!

You don't want to add an array as a new item in your ArrayList, you want to add the items in the array. Use the AddRange to add a range of objects.
mmmhhh.. I'm not sure this would be the case.. it really depends on how the data is to be represented internally. Using addrange will cause an arraylist to contain all the cells from a particular line, in one vertical column. If you repeatedly addrange then your file taht looks like this:

a,b,c
1,2,3
d,e,f
4,5,6

ends up in an arraylist of length 12 like this:
a
b
c
1
2
3
d
e
f
4
5
6

i.e. you lose the identity of the lines


Also, String and String() are the same, they are both data types, but objects of each will be different type objects.
I think you mean to say:
Dim x as String()
Dim x() as String

are the same (result)? In data type terms, a string object is different to an array object holding string types - both are objects, but they arent the same thing?

The reason both convensions exist is because of the different contexts you have to use one or the other. For instance when declaring an array with an initial number of elements you can't say 'Dim x As String(10)', you get an error 'array bound cannot appear in type specifiers'. You have to do 'Dim x(10) As String'. String is a type and String() is a type but String(10) is not a type.

I think this is one of those cases where VBs reuse of () to denote array as well as function makes the language a truly awful mess. In C#, java and other C-like variants, square brackets are used to denote array and array lengths:

string[] x = new string[10];
string x = new String("hello");

VB cannot make this distinction, which is a shame, because you then end up with somewhat inconsistent/messy declarations as:
Dim x as String() 'reads: x as string array
Dim x() as String 'reads: x is an array of string
Dim x(10) as String 'reads: x is an array size 11 of string
Dim x(0 to 10) as String 'reads: x is an array running from 0 to 10 of string

why 11? because 10 denotes the last accessible position..

All of them are just a wee bit yuck, they dont read right, and MS should have scrapped () for arrays and gone with something else.. the 0 to 10 syntax is probably the best, but if one is to use Type() to mean "array of type" then it shouldnt break as soon as you try to size it..

Dim x as String() = New String(10)
doesnt work either, because VB thinks youre trying to make a new String object, passing in 10 as a parameter to the constructor, and then assigning this to an array of string. I forget where it complains, but it cant be done..

However, if we tell VB is is an array with {} (normally reserved for preinitialization of an array) then it's quite happy..

Dim x as String() = New String(10){}

but you cannot (nor should you) shorten this to:

Dim x as New String(10){}


but do remember the kick in the backside: that the array declared in such a manner runs from 0 to 10, not 0 to 9 as in c/java, so you end up with an array of 11.



Your last question: shouldn't a single dimentional array of String()'s be a multidimentional array of Strings?
If you try to do this 'Dim x(10) As String()' you'll get an error saying 'array modifiers cannot be specified on both the variable and its type'. So there you have it, a case where type String() cannot be used.
a good question that further highlights the mess inherent..

You can indeed to multidim arrays in VB, through the rather ungainly syntax of :
Dim x()() as String = { New String(10){}, New String(10){}, New String(10){}}

We now have an array that can be accessed with:
x(N)(M) where N is a number from 0 to 2 inclusive, and M is a number from 0 to the size of the array at that location.. In this case we have made an array 3 x 11.. in c# the equivalent would be:

string[][] x = new string[3][11];


VB has a rectangular syntax to make up for this:

Dim x(2,10) As String

But you cant use this in any other form as VB only takes size initializers for top level arrays:

Dim x as String()() = New String(2)(10) {}


-
Now, down to the problem..

Given that you want to combine 2 files into 1, i can kinda guess at the rules that make it happen, but I'd need to know if you are always going to find the same lines in each file, in the same order. If you are, then thats great.. But if the lines in the files may be in different orders, or file 1 will one day fail to contain 0001, Fred (but file 2 still does) then you'lll have a problem

The following code might make things easier for your task:

VB.NET:
'this function takes a full path to a CSV file as a parameter and returns
'the contents of the file in a List object. The items in the list are organised
'in the same order as the lines are in the file
'each entry in the list is an array of strings denoting all the cells found
'on the line in the csv file
      Private Function readCSVIntoTypedList(ByVal pathname As String) As System.Collections.Generic.List(Of String())

        Dim reader As Microsoft.VisualBasic.FileIO.TextFieldParser
        reader = My.Computer.FileSystem.OpenTextFieldParser(pathName)
        reader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
        reader.SetDelimiters(",")

        Dim toReturn As New System.Collections.Generic.List(Of String())
        Dim currentRow As String()
        While Not reader.EndOfData
            Try
                currentRow = reader.ReadFields()

                toReturn.Add(currentRow)

            Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
                MsgBox("Line " & ex.Message & _
                "is not valid and will be skipped.")
            End Try
        End While

        Return toReturn

    End Function

this function is crucial and helpful, as noted in the comment we will effectively end up with a list in memory that represents the file on disk. the list item 0 represents the first line.

So now we have the capability to read our files, we read them in:

VB.NET:
  Dim f1 as System.Collections.Generic.List(of String())
  Dim f2 as System.Collections.Generic.List(of String())
  Dim res as System.Collections.Generic.List(of String())

  f1 = readCSVIntoList("C:\temp\file1.csv")
  f2 = readCSVIntoList("C:\temp\file2.csv")

  If f1.Count <> f2.Count Then
    Throw New Exception("The files have different numbers of lines. This isnt supported")

  'now we have both files in memory, lets make the result list, res, able to have the
  'capacity to store all the items it needs to
  res.Capacity = f1.Count

  'skip over the lists
  For i as Integer = 0 to f1.Count-1

    'because both our lists are typed OF STRING() it means they can 
    'be treated as string arrays without casting
    'f1.Item(0) and f1(0) both get the item at position 0
    If f1(i).Length < 2 Or f2(i).Length < 2 Then
      Throw New Exception("A line in one of the files doesnt have enough cells to perform this operation")

    ' the item in the list is an array and can be indexed like an array would
    'this line says "set the item in the res list at position i to be a new string array
    'f1(i) returns us a string array that has a 0 and a 1 index..
    res(i) = New String(3){ f1(i)(0), f1(i)(1), f2(i)(1) }

  Next i


  'now lets skip over each item in our result list, jsut because we are bored :)

  For Each x as String() in res
    MessageBox.Show("Got an array of length " & x.Length & " in my res! :)")

    'remember x is a string array
    MessageBox.Show(String.Format("The items are: {0}, {1}, {2}", x))
  Next x


Object lessons here are:
Throw arrays away as much as possible; theyre a pain in the backside because they are so inflexible. Easy to understand and been around since the beginning of time, but they make things such hard work sometimes! :)

Here, we preserve the structure of our file, rather than using AddRange which would destroy it. Note I could have used an arraylist to do all this, but ArrayList isnt typed.. it takes in objects and returns objects. You have to remember what type they are and cast to and from the types yourself.. major nuisance! Typed Lists on the other hand.. beautiful! every item behaves like an array.. and we can quickly and easily generate a 2D structure using them...

Note that we use lists because they automatically grow in a relatively resource cheap fashion, whereas an array is fixed, unless you redim preserve it all the time - doing that can potentially involve huge amounts of data copying around memory. Ugh.
 

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,517
Location
Norway
Programming Experience
10+
cjard said:
I think you mean to say:
Dim x as String()
Dim x() as String

are the same (result)? In data type terms, a string object is different to an array object holding string types - both are objects, but they arent the same thing?
No. An object and a type is not the same thing. The type describes the nature of an object, you can have this type of object or another type of object. This is something you either not understand yourself, or are deliberately trying to confuse other users of this forum with.

What I marked in red in your quote is the type specifiers. The green () is called array modifiers. The resulting objects stored both in x variable are the same type of objects because the single String object was modified to an array, so the resulting type of both those example are string arrays. And as I already said, an array of strings and a string array is the same thing. Array also signifies a type of object, ie a collection, that an object is an array tells you that the object is a container, which may contain other objects whatever type. Mixing array into this discussion is really a shame, because it confuses the beginner trying to understand OOP, objects and types.

My example was this (as implied by your statement I replied to: "A string and an array of Strings are not the same"):
Dim x as String()
Dim x as String
Marked in red is the types, they are different types, but they are still both types. The resulting objects stored both in x variable are different type objects.

Strong typing is much more important in VB.Net than in previous VB versions, therefore it is important to know what types are. To know what types are is it crucial to understand and being able to distinguish them from their derived objects. Abstraction is the number one key concept in object oriented programming. Equal to the inbuilt system types you can define your own type with a class or a structure. A class is a type. Wiki is good:
Class: a class defines the abstract characteristics of a thing
Object: a particular instance of a class
 
Status
Not open for further replies.
Top Bottom