Declaring a jagged or rectangular array

Doing so in flight, that is plubic / global

Page 1 of 1

8 Replies - 7304 Views - Last Post: 15 October 2010 - 12:08 PM Rate Topic: -----

#1 Palmore  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 11
  • Joined: 17-August 09

Declaring a jagged or rectangular array

Posted 21 September 2010 - 07:04 PM

I'm still very new to VB.net, no formal training... Unless you count a Turbo Pascal 7 class I had in High School...Anyway =)

I'm working on a reporting section of code for an inventory app I'm making for my office.

I call a text file, read every line into an array then populate information pages with what has been pulled from the text file.

For reporting, I want to read every text file in the directory, reading each one into a multidimensional array.

Thus I can call and report on each item, i.e.

ItemArray(i,2) would be all systems with Windows 2008 EE

I have code that lists all files in the desired directory and counts each file, so I eventually get counts of how deep I need the first level of the jagged array to be. but not until after code execution.

Basically how can I write each array of data to the jagged array.

MainMenu

    Public ItmOptions As New List(Of String)

    Public ItemArray()()





    Public Sub ReadFileForReports()

        Dim oRead As System.IO.StreamReader
        Dim i As Integer = 0

        'Items.Clear()

        ' Try opening INI file
        Try
            oRead = IO.File.OpenText(MainMenu.DirRoot & MainMenu.DirEnviroment & MainMenu.DirCategory & MainMenu.LoadFile)
        Catch e5 As Exception
            ' No INI found
            MsgBox("No INI File found")
            Exit Sub
        End Try

        While oRead.Peek <> -1
            MainMenu.ItmOptions.Add(oRead.ReadLine())
        End While
        oRead.Close()
        oRead.Dispose()

        MainMenu.ItmOptions.ToArray()


    End Sub

    Public Sub GatherReportsArray()

        Dim TempCategory As String = "ServerSystems"
        Dim TempEnviroment As String = "Prod\"


        Dim i As Integer = 0



        If MainMenu.tscombo_Enviroment.SelectedIndex = 1 Then TempEnviroment = "Prod\"
        If MainMenu.tscombo_Enviroment.SelectedIndex = 2 Then TempEnviroment = "Dev-UAT\"
        If MainMenu.tscombo_Enviroment.SelectedIndex = 3 Then TempEnviroment = "Test\"
        If MainMenu.tscombo_Enviroment.SelectedIndex = 4 Then TempEnviroment = "Sandbox\"

        If MainMenu.combo_Category.SelectedIndex = 0 Then TempCategory = "ServerSystems\"
        If MainMenu.combo_Category.SelectedIndex = 1 Then TempCategory = "ServerApplications\"
        If MainMenu.combo_Category.SelectedIndex = 2 Then TempCategory = "NetworkSystems\"
        If MainMenu.combo_Category.SelectedIndex = 3 Then TempCategory = "NetworkApplications\"
        If MainMenu.combo_Category.SelectedIndex = 4 Then TempCategory = "DesktopSystems\"
        If MainMenu.combo_Category.SelectedIndex = 5 Then TempCategory = "DesktopApplications\"
        If MainMenu.combo_Category.SelectedIndex = 6 Then TempCategory = "Databases\"

        Dim Dir As New IO.DirectoryInfo(MainMenu.DirRoot & TempEnviroment & TempCategory)
        Dim ArrayFiles As IO.FileInfo() = Dir.GetFiles("*.ini")
        Dim Files As IO.FileInfo

        ' Count Systems

        MsgBox(MainMenu.DirRoot & TempEnviroment & TempCategory)


        For Each Files In ArrayFiles

            MainMenu.LoadFile = Files.Name
            MsgBox(MainMenu.LoadFile)
            ReadFileForReports()
            MsgBox(i)
            MainMenu.ItemArray(i) = MainMenu.ItmOptions(i)

            i = i + 1

        Next

    End Sub




I get an error at MainMenu.ItmOptions(i)

Error 1 Value of type 'String' cannot be converted to '1-dimensional array of Object'.

As seen above, MainMenu.ItmOptions is a List(of String) that is then converted to an array MainMenu.ItmOptions.ToArray

How can I achieve writing the data in MainMenu.ItmOptions() into i of MainMenu.ItemArray


It hit me as I was typing this out to try reading each item in ItmOptions and writing each into MainMenu.ItemArray(i,i2)

i.e.


Dim i2 as Integer = 0

Do until i = MainMenu.ItmOptions.Count
   MainMenu.ItemArray(i, i2) = MainMenu.ItmOptions(i2)
   i2 = i2 + 1
Loop




Rather than trying than the original code. I'll test this, but didn't wanna waste this long post after typing it all out lol.

What I tried

        
For Each Files In ArrayFiles

            MainMenu.LoadFile = Files.Name
            MsgBox(MainMenu.LoadFile)
            ReadFileForReports()
            MsgBox(i)

            Dim i2 As Integer = 0

            Do Until i = MainMenu.ItmOptions.Count
                MainMenu.ItemArray(i)(i2) = MainMenu.ItmOptions(i2)
                i2 = i2 + 1
            Loop

            i = i + 1

        Next



But I get a null reference exception. "Use the new keyword to create an object instance"

Being very new to VB, how can I achieve my end goal?

Thanks

Is This A Good Question/Topic? 0
  • +

Replies To: Declaring a jagged or rectangular array

#2 demausdauth  Icon User is online

  • D.I.C Addict
  • member icon

Reputation: 174
  • View blog
  • Posts: 629
  • Joined: 03-February 10

Re: Declaring a jagged or rectangular array

Posted 22 September 2010 - 07:56 AM

While I think you are on a pretty good approach, I would like to offer my 2 cents...

Public Sub ReadFileForReports()

    Dim oRead As System.IO.StreamReader
    Dim i As Integer = 0

    'Items.Clear()

    ' Try opening INI file
    Try
        oRead = IO.File.OpenText(MainMenu.DirRoot & MainMenu.DirEnviroment & MainMenu.DirCategory & MainMenu.LoadFile)
    Catch e5 As Exception
        ' No INI found
        MsgBox("No INI File found")
        Exit Sub
    End Try

    While oRead.Peek <> -1
        MainMenu.ItmOptions.Add(oRead.ReadLine())
    End While
    oRead.Close()
    oRead.Dispose()

    MainMenu.ItmOptions.ToArray()


End Sub


This is pretty good with a few exceptions/improvements/opinions...

1)I would make use of the Using statement for the file objects.
2)Calling the .ToArray method of ItmOptions makes no sense as this function returns an array and it is not being assigned to anything.

Public Sub GatherReportsArray()

    Dim TempCategory As String = "ServerSystems"
    Dim TempEnviroment As String = "Prod\"


    Dim i As Integer = 0



    If MainMenu.tscombo_Enviroment.SelectedIndex = 1 Then TempEnviroment = "Prod\"
    If MainMenu.tscombo_Enviroment.SelectedIndex = 2 Then TempEnviroment = "Dev-UAT\"
    If MainMenu.tscombo_Enviroment.SelectedIndex = 3 Then TempEnviroment = "Test\"
    If MainMenu.tscombo_Enviroment.SelectedIndex = 4 Then TempEnviroment = "Sandbox\"

    If MainMenu.combo_Category.SelectedIndex = 0 Then TempCategory = "ServerSystems\"
    If MainMenu.combo_Category.SelectedIndex = 1 Then TempCategory = "ServerApplications\"
    If MainMenu.combo_Category.SelectedIndex = 2 Then TempCategory = "NetworkSystems\"
    If MainMenu.combo_Category.SelectedIndex = 3 Then TempCategory = "NetworkApplications\"
    If MainMenu.combo_Category.SelectedIndex = 4 Then TempCategory = "DesktopSystems\"
    If MainMenu.combo_Category.SelectedIndex = 5 Then TempCategory = "DesktopApplications\"
    If MainMenu.combo_Category.SelectedIndex = 6 Then TempCategory = "Databases\"

    Dim Dir As New IO.DirectoryInfo(MainMenu.DirRoot & TempEnviroment & TempCategory)
    Dim ArrayFiles As IO.FileInfo() = Dir.GetFiles("*.ini")
    Dim Files As IO.FileInfo

    ' Count Systems

    MsgBox(MainMenu.DirRoot & TempEnviroment & TempCategory)


    For Each Files In ArrayFiles

        MainMenu.LoadFile = Files.Name
        MsgBox(MainMenu.LoadFile)
        ReadFileForReports()
        MsgBox(i)
        MainMenu.ItemArray(i) = MainMenu.ItmOptions(i)

        i = i + 1

    Next

End Sub


3)GatherReportsArray (imho) does too much for what it appears that it should be doing.
4)The .SelectedIndex are better off done in SelectedIndexChange events for the corresponding control. And then setting a class level variable with the specific information. After all this method should be about gathering information that is set somewhere else :) .
5) Replace MsgBox with MessageBox.Show -- the MsgBox method actually is a 2 step process whereby it calls MessageBox.Show itself.


My entire approach based on the presented code and comments.
    Public Class HelpDeclaringAJaggedArray

        Private _FileCategory As String = "ServerSystems"
        Private _FileEnvironment As String = "Prod"
        Private _FileDirectoryRoot As String = String.Empty
        Private _DirectoryFileContents As Dictionary(Of String, List(Of String))


        Public ReadOnly Property FileCategory() As String
            Get
                Return _FileCategory
            End Get
        End Property

        Public ReadOnly Property FileEnvironment() As String
            Get
                Return _FileEnvironment
            End Get
        End Property

        Public ReadOnly Property DirectoryRoot() As String
            Get
                Return _FileDirectoryRoot
            End Get
        End Property


        Public Function ReadFile(ByVal fileToRead As FileInfo) As List(Of String)

            'Create empty return object
            Dim readLines As List(Of String) = New List(Of String)

            Try
                If fileToRead.Exists Then
                    'Using allows for automatic disposal of objects
                    Using fileReader As StreamReader = fileToRead.OpenText()
                        'loop until end of file
                        Do While Not fileReader.EndOfStream
                            'load the values of each line into the return List object
                            readLines.Add(fileReader.ReadLine())
                        Loop
                    End Using
                End If

            Catch ex As IOException
                MessageBox.Show("Error while processing the file.")

            Catch ex As Exception
                MessageBox.Show("Error reading in file data.")
            End Try

            Return readLines
        End Function

        Public Sub GatherReportInfo()

            'check that we have all the parts to build the directory path
            If (Not String.IsNullOrEmpty(DirectoryRoot) AndAlso Not String.IsNullOrEmpty(FileEnvironment) AndAlso Not String.IsNullOrEmpty(FileCategory)) Then

                'build the directory path
                Dim directoryPath As New DirectoryInfo(My.Computer.FileSystem.CombinePath(My.Computer.FileSystem.CombinePath(DirectoryRoot, FileEnvironment), FileCategory))

                'create object to hold contents of directory files, also will clear old values
                _DirectoryFileContents = New Dictionary(Of String, List(Of String))

                Dim fileContents As List(Of String) = New List(Of String)

                For Each fiFile In directoryPath.GetFiles("*.ini")
                    'get the contents of the file
                    fileContents = ReadFile(fiFile)

                    'check to make sure there are contents to the file
                    If (fileContents.Count > 0) Then
                        MainMenu.LoadFile = fiFile.Name

                        'store file contents by filename (unique within a directory) to class level dictionary
                        _DirectoryFileContents.Add(fiFile.Name, fileContents)

                    End If
                Next
            End If
        End Sub

        'various event handlers to set class variables
        '_FileCategory , _FileEnvironment , _FileDirectoryRoot 

    End Class


Was This Post Helpful? 1
  • +
  • -

#3 Palmore  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 11
  • Joined: 17-August 09

Re: Declaring a jagged or rectangular array

Posted 22 September 2010 - 09:53 AM

Great!


_DirectoryFileContents = New Dictionary(Of String, List(Of String))

was the secret sauce I was looking for, that did the trick of exactly my end goal!

Again, I'm not used to object based coding, being from a Turbo Pascal / DOS day since i last coded, I do everything the hard way lol.

Thanks also for the extra tips and improvements! I'll modify my code to reflect those, I can't tell you how giddy I am I can finally start building the report functions for the code!


Thank you.
Was This Post Helpful? 0
  • +
  • -

#4 Palmore  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 11
  • Joined: 17-August 09

Re: Declaring a jagged or rectangular array

Posted 10 October 2010 - 08:28 AM

Well I've finally gotten around to actually testing and working more with the code above and I've ran into an issue...

when I add items to the Jagged Array, the item adds fine, everything populates and the world is happy.
I put a break point in at the ItemArray.Add(i, ItmOptions) too see what was going on.

It does populate ItemArray(i) with all the data in ItmOptions, cept every prior value in ItemArray is overwritten by ItmOptions.

This rather than ItemArray(1) and ItemArray(2) being different sets of data, when value 1 is written to ItemArray(1) it has the value of 1, when data from 2 is written to ItemArray(2), ItemArray(1) and ItemArray(2) now have the data of 2 and so on.


    Public ItemArray As Dictionary(Of String, List(Of String))
    Public ItmOptions As New List(Of String)

        For Each Files In ArrayFiles

            LoadFile = Files.Name
            FileOps.ReadFileForReports()
            ItemArray.Add(i, ItmOptions)

            i = i + 1

        Next



Ideas?
Was This Post Helpful? 0
  • +
  • -

#5 demausdauth  Icon User is online

  • D.I.C Addict
  • member icon

Reputation: 174
  • View blog
  • Posts: 629
  • Joined: 03-February 10

Re: Declaring a jagged or rectangular array

Posted 11 October 2010 - 06:29 AM

What I am pretty sure that is happening is that the scope of ItemOptions is at the class level and you are reusing the current instance of the object rather than creating a new one. So when you change it's value for each loop and add it to the dictionary again it changes all other references to the same ItemOptions, because you are still working with the same instance.

This is why in my example the ReadFile function creates a List and returns the List object. The list of file lines would not get overwritten by other file reads.
Was This Post Helpful? 0
  • +
  • -

#6 Palmore  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 11
  • Joined: 17-August 09

Re: Declaring a jagged or rectangular array

Posted 14 October 2010 - 07:05 PM

Ahhh ok ok, I think I'm grasping it now!

Heres what I ended up using from your example

    Public Sub GatherReportsArray()

        If MainMenu.tscombo_Enviroment.SelectedIndex = 0 Then

            MsgBox("Please choose an Environment other than All")
            Exit Sub

        End If

        Dim fileContents As List(Of String) = New List(Of String)
        Dim directoryPath As New DirectoryInfo(MainMenu.DirRoot & MainMenu.DirEnviroment & MainMenu.DirCategory)
        Dim i As Integer = 0

        'create object to hold contents of directory files, also will clear old values
        MainMenu.ItemArray = New Dictionary(Of String, List(Of String))

        For Each fiFile In directoryPath.GetFiles("*.ini")
            'get the contents of the file
            fileContents = ReadFile(fiFile)

            'check to make sure there are contents to the file
            If (fileContents.Count > 0) Then

                MainMenu.ItemArray.Add(i, fileContents)

                i = i + 1

            End If
        Next

    End Sub



Now out of curiosity, if you've noticed I changed the dictionary key to an integer 0 - x, will this cause issues if I change environments and run the gatherReportsArray sub routine again?

Reason I ask, is how I plan on building the reports (easier if I utilize an integer rather than file name), that and between environments some system names will be the same.

Thanx again for your help!
Was This Post Helpful? 0
  • +
  • -

#7 demausdauth  Icon User is online

  • D.I.C Addict
  • member icon

Reputation: 174
  • View blog
  • Posts: 629
  • Joined: 03-February 10

Re: Declaring a jagged or rectangular array

Posted 15 October 2010 - 06:14 AM

If you are going to use a 0 based integer index for the dictionary object, then instead of a dictionary you could use a List instead. I don't know how much overhead there is to the Dictionary vs List but I would think that the fact that the Dictionary has to track more information would make it a bit higher.

And actually you did not change it to an integer -- the MainMenu.ItemArray is still being declared as Dictionary(Of String, List(Of String)). As I said you could just as well use a List(Of List(Of String)), this way you would not have to do the i = i + 1 because each time you add to the MainMenu.ItemArray it would automatically create the index for you.

My question to you though is how do you know which files content you need for a report if you are going to pull it by index? What if there is one more file in the directory than you anticipate, will that throw your file-report-index scheme off?
Was This Post Helpful? 0
  • +
  • -

#8 Palmore  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 11
  • Joined: 17-August 09

Re: Declaring a jagged or rectangular array

Posted 15 October 2010 - 10:50 AM

I was meaning I changed the key index to an integer, i.e.

_DirectoryFileContents.Add(fiFile.Name, fileContents)

to

MainMenu.ItemArray.Add(i, fileContents)

But good idea with the List, would I have to change either of the rest of my code to do this? or just declare it as a list of string rather than dictionary? and aside from the obvious

MainMenu.ItemArray.Add(fileContents)



As for reporting, here is the jist of what I'm doing (exmaple report that only pulls the server names)

* Build Array for reporting

    Public Sub GatherReportsArray()

        Dim fileContents As List(Of String) = New List(Of String)
        Dim directoryPath As New DirectoryInfo(MainMenu.DirRoot & MainMenu.DirEnviroment & MainMenu.DirCategory)
        Dim i As Integer = 0

        'create object to hold contents of directory files, also will clear old values
        MainMenu.ItemArray = New Dictionary(Of String, List(Of String))

        For Each fiFile In directoryPath.GetFiles("*.ini")
            'get the contents of the file
            fileContents = ReadFile(fiFile)

            'check to make sure there are contents to the file
            If (fileContents.Count > 0) Then
                'MainMenu.LoadFile = fiFile.Name
                'store file contents by filename (unique within a directory) to class level dictionary
                MainMenu.ItemArray.Add(i, fileContents)

                i = i + 1

            End If
        Next

    End Sub




* Test report view, this calls place 1 in each top level system in the array (1,1...2,1...3,1 and so on)

    Private Sub tsbttn_View_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tsbttn_View.Click

        If tscombo_Enviroment.SelectedIndex = 0 Then Exit Sub

        FileOps.GatherReportsArray()
        ReviewPoll.txt_Review.Text = ""

        Dim i As Integer = 0
        Do Until i = MainMenu.ItemArray.Count
            ReviewPoll.txt_Review.Text = ReviewPoll.txt_Review.Text & vbCrLf & MainMenu.ItemArray(i)(1)
            i = i + 1
        Loop

        Call ReviewPoll.Show()

    End Sub



This way, I build the array once I have chosen what items I wish to report on and depend on the ItemArray.Count to know how many systems I'm reporting against.

I can then use Do Until i = count and use i as the Key, the second number will be changed depending on what they wish to report on, i.e.

1 - Server Name
2 - Server OS

and so on.

An example for detecting OS would be (simple example I have more data that will build this such as prepopulated OS options etc.)

    Private Sub BuildReport_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BuildReport.Click

        If tscombo_Enviroment.SelectedIndex = 0 Then Exit Sub

        FileOps.GatherReportsArray()
        ReviewPoll.txt_Review.Text = ""

        Dim i As Integer = 0
        Do Until i = MainMenu.ItemArray.Count
            If MainMenu.ItemArray(i)(2) = "Windows 2003 Server" Then
                   ReviewPoll.txt_Review.Text = ReviewPoll.txt_Review.Text & vbCrLf & MainMenu.ItemArray(i)(2)
                   i = i + 1
            End If
        Loop

        Call ReviewPoll.Show()

    End Sub



Then when I call ReviewPoll.Show it will display ReviewPoll.txt_Review.Text containing all systems with Windows 2003 Server installed.


Again please keep in mind my code sucks and is sloppy, mainly cause I've only ever coded in Turbo Pascal 7 =) and never really object oriented languages.

Thanks again for all your help, it's very appreciated.

This post has been edited by Palmore: 15 October 2010 - 10:50 AM

Was This Post Helpful? 0
  • +
  • -

#9 demausdauth  Icon User is online

  • D.I.C Addict
  • member icon

Reputation: 174
  • View blog
  • Posts: 629
  • Joined: 03-February 10

Re: Declaring a jagged or rectangular array

Posted 15 October 2010 - 12:08 PM

To make MainMenu.ItemArray a List instead of a dictionary you declare it
MainMenu.ItemArray = New List(Of List(Of String))

'and to add to it
MainMenu.ItemArray.Add(filecontents)



If I have understood your process of building the reports, then you may be able to use this general function for all your reports, just pass in your level. You might have separate buttons but each of them can call this function passing in the level, which you may be able to get from tscombo_Environment. Course it could be all hooey too :) !



Private Sub MakeReport(ByVal level As Integer)
     
     If Not tscombo_Environment.SelectedIndex = 0 Then
          
          FileOps.GatherReportsArray()
          
          'Get an instance of the ReviewPoll form
          Dim frmReviewPoll As new ReviewPoll

          'by getting the new instance it should clear the text box already
          
          'loop through the dictionary
          'we use the level value that was passed in to tell which value of the ItemArray that we
          ' want.
          For i As Integer = 0 To MainMenu.ItemArray.Count -1
               frmReviewPoll.txt_Review.Text &= (Environment.NewLine & MainMenu.ItemArray(i)(level))
          Next
          
          'IMO you should show the report as a modal dialog but that is not how your original code is
          'frmReviewPoll.ShowDialog()
          frmReviewPoll.Show()

     End If
End Sub



At the very least you can replace the Do Until ... Loop with the For loop in this last bit of code.

The Environment.NewLine is preferable to vbCrLf, I believe because not cultures are the same and so vbCrLf might not work around the world (not so sure on this).

The &= is a concatenation operator, what it means concatenate anything on the left with anything on the right side and reassign the whole back to the original variable.

While Exit Sub is valid, I just don't like using -- it bothers me :D , that's why I wrapped everything in the If statement for the selectedindex.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1