Multidimensional Arrays using Dictionaries - vb.net

I am trying to make a multidimensional associative array. I want it so I can have something like:
someVar(date)(hour)(category) = mssql query
I am using the following to try and prepare but am having trouble adding data to the array.
Dim test As New Dictionary(Of Integer, Dictionary(Of String, String))
Dim test2 As New Dictionary(Of String, String)
Any help is greatly appreciated.
-----EDIT:
Here is what I am using, it works as desired. Doe ayone see why this would be a bad way to do it?
Dim test As New Dictionary(Of Integer, Dictionary(Of String, String))
Dim SomeNum As Integer = 0
Dim someStr As String = "This is a string: "
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
While SomeNum < 100
Dim someNum2 As Integer = 0
Dim test2 As New Dictionary(Of String, String)
While someNum2 < 100
test2.Add(CType(someNum2, String), someStr & CType(someNum2, String))
someNum2 += 1
End While
test.Add(SomeNum, test2)
SomeNum += 1
End While
For Each kvp As KeyValuePair(Of Integer, Dictionary(Of String, String)) In test
Dim ccc As String = ""
Dim ddd As String = ""
Dim v1 As String = CType(kvp.Key, String)
Dim v2 As Dictionary(Of String, String) = kvp.Value
lblOne.Items.Add("Key: " & v1)
For Each kvp2 As KeyValuePair(Of String, String) In v2
Dim v3 As String = kvp2.Key
Dim v4 As String = kvp2.Value
lblTwo.Items.Add("SubKey: " & v3 & " Value: " & v4)
lblOne.Items.Add("")
Next
lblOne.Items.Add(v1 & " End--------------")
lblTwo.Items.Add(v1 & " End--------------")
Next
End Sub

Create a class with properties "Date", "HourlySales", "Category".
Public Class Sales
Public Property SalesDate() As Date
Public Property HourlySales() As Decimal
Public Property Category() As String
Public Sub New()
End Sub
Public Sub New(vSalesDate As Date, vHourlySales As Decimal, vCategory As String)
SalesDate = vSalesDate
HourlySales = vHourlySales
Category = vCategory
End Sub
End Class
Create a list of objects of type Sales
Shared Function GetSales() As List(Of Sales)
Dim SalesList As New List(Of Sales)
Using connection As New SqlConnection(YourConnectionString)
Dim cmd As SqlCommand = New SqlCommand("SelectSalesList", connection)
cmd.CommandType = CommandType.StoredProcedure
cmd.Connection.Open()
Dim reader As SqlDataReader = cmd.ExecuteReader()
While reader.Read
SalesList.Add(New Sales(reader("SalesDate"), reader("HourlySales"), reader("Category")))
End While
End Using
Return SalesList
End Function
You can call the GetSales() function to return a list of Sales.

Look into Entity Framework it makes objects out of your database.
MSDN EF
For a custom array, you may find a Tuple useful.

A dictionary of dictionary of dictionaries is a maintenance nightmare, to query and debug.
I suggest to have a composite key instead, so instead of doing 3 lookups you would just do one for a string of date+hour+category. For example, date=Monday, hour=9PM, category=Apples, your key is Monday:9PM:Apples (I picked colon as parts separator, but you can choose a different character).

Related

Using dictionary within structures

I have a structure that has a string and 2 dictionary variable. I don't know how to insert data into these dictionaries.
Public Structure librariesWithMedia
Dim strLibraryName As String
Dim dicBooksMedia As SortedDictionary(Of String, String)
Dim dicNonBooksMedia As SortedDictionary(Of String, String)
End Structure
Dim libraryMediaEntry As librariesWithMedia
This is my structure and this is how I'm storing the values.
libraryMediaEntry.dicBooksMedia.Add(key, value)
This gives me a null reference exception error. Can anyone help me understand and how I would have to take the data?
Your Structure MUST initialise/instantiate the dictionaries before you can use them.
Public Structure librariesWithMedia
'
Dim strLibraryName As String
Dim dicBooksMedia As SortedDictionary(Of String, String)
Dim dicNonBooksMedia As SortedDictionary(Of String, String)
'
Sub New(LibName As String)
strLibraryName = LibName
dicBooksMedia = New SortedDictionary(Of String, String)
dicNonBooksMedia = New SortedDictionary(Of String, String)
End Sub
'
End Structure
'
Dim libraryMediaEntry As librariesWithMedia
And then in your code, for example
Sub DoSomethingProcess()
'
libraryMediaEntry = New librariesWithMedia("Featured_Books")
libraryMediaEntry.dicBooksMedia.Add("James A Michener", "Chesapeake")
'
End Sub

Getting Installed Steam Games From Registry

Can someone help me with this error I'm getting? Error14 'Using' operand of type 'System.Collections.Generic.List(Of String)' must implement 'System.IDisposable'
Public Function GetInstalledGames() As Object
Dim enumerator As IEnumerator(Of String) = Nothing
Dim list As List(Of String) = Directory.GetFiles(String.Concat(Me.SteamPath, "\steamapps")).ToList()
Using strs As List(Of String) = New List(Of String)()
enumerator = list.Distinct().GetEnumerator()
While enumerator.MoveNext()
Dim current As String = enumerator.Current
If (current.Contains("appmanifest_") And current.Contains(".acf")) Then
strs.Add(Path.GetFileName(current).Replace("appmanifest_", "").Replace(".acf", ""))
End If
End While
End Using
Return strs
End Function
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
Dim enumerator As IEnumerator(Of String) = Nothing
Me.tbOutput.Text = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
Me.SteamPath = Conversions.ToString(Me.GetSteamPath())
Using installedGames As List(Of String) = DirectCast(Me.GetInstalledGames(), List(Of String))
enumerator = installedGames.Distinct().GetEnumerator()
While enumerator.MoveNext()
Dim current As String = enumerator.Current
Me.lbGames.Items.Add(current)
End While
End Using
End Sub
Stop writing explicit enumerator loops for no reason
Make your functions return types that make sense instead of Object
Don’t sprinkle Using into code without knowing what it does
Pass data between functions through arguments, not class fields
Private Shared Function GetInstalledGames(steamPath As String) As IEnumerable(Of String)
Dim result As New List(Of String)
For Each name In Directory.GetFiles(Path.Combine(steamPath, "steamapps"))
If name.Contains("appmanifest_") AndAlso name.Contains(".acf") Then
result.Add(Path.GetFileNameWithoutExtension(name).Replace("appmanifest_", ""))
End If
Next
Return result
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs)
Me.tbOutput.Text = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
Dim steamPath As String = Me.GetSteamPath()
For Each current In GetInstalledGames(steamPath).Distinct()
Me.lbGames.Items.Add(current)
Next
End Sub

vb.net - combo box always select the first value

Good day, Can anyone help me with this problem. I have two a combo box for months(01-12) for monthstart and monthend. Now, everytime I select October(10), the value it show is 01. Sorry. I am new in vb.
Is there any alternative way to do this? Any suggestions?
Thanks.
Private Sub ValueComboxformonth()
Dim comboSource As New Dictionary(Of String, String)()
comboSource.Add("01", "January")
comboSource.Add("02", "February")
comboSource.Add("03", "March")
comboSource.Add("04", "April")
comboSource.Add("05", "May")
comboSource.Add("06", "June")
comboSource.Add("07", "July")
comboSource.Add("08", "August")
comboSource.Add("09", "September")
comboSource.Add("10", "October")
comboSource.Add("11", "November")
comboSource.Add("12", "December")
cmbAppliedMonthStart.DataSource = New BindingSource(comboSource, Nothing)
cmbAppliedMonthStart.DisplayMember = "Value"
cmbAppliedMonthStart.ValueMember = "Key"
cmbAppliedMonthEnd.DataSource = New BindingSource(comboSource, Nothing)
cmbAppliedMonthEnd.DisplayMember = "Value"
cmbAppliedMonthEnd.ValueMember = "Key"
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
ValueComboxformonth()
Dim monthkeystart As String = DirectCast(cmbAppliedMonthStart.SelectedItem, KeyValuePair(Of String, String)).Key
Dim monthvaluestart As String = DirectCast(cmbAppliedMonthStart.SelectedItem, KeyValuePair(Of String, String)).Value
Dim monthkeyend As String = DirectCast(cmbAppliedMonthEnd.SelectedItem, KeyValuePair(Of String, String)).Key
Dim monthvalueend As String = DirectCast(cmbAppliedMonthEnd.SelectedItem, KeyValuePair(Of String, String)).Value
End Sub
The value of monthkeystart is 01
The value of monthvaluestart is January
This is due to you calling the ValueComboxformonth method before reading the values. That method resets the datasource for the combo-boxes, and it defaults to the first value.
Try moving that call to the constructor (New method) of the form.
Public Sub New()
...
ValueComboxformonth()
End Sub

Looping through Dictionary(Of String, List(Of String))

Similar question here, but no answer : vb.net dictionary of string,dictionary...after filling readout always empty
I fill as List(Of String) with rows of text from a file and then add it to a Dictionary. The method I use to fill this Dictionary works as it should. I create:
Private dictDictionary As Dictionary(Of String, List(Of String))
loop through the text file and adding each row to a list then add that list to the dictionary with the file name as key like so:
dictDictionary.Add(sFileName, sFileRows)
sFileRows is a List(Of String) containing a MAX of 1056 elements that I need to move around based on specific options. The problem I'm having is accessing this List(Of Strings) by the Key.
I've tried:
For Each kvp As KeyValuePair(Of String, List(Of String)) In dictDictionary
Dim sKey As String = kvp.Key
Dim tempRows As List(Of String) = New List(Of String)
tempRows = dictDictionary.item(sKey)
Next
No matter what I try when I assign the List(Of String) in the Dictionary to a new List it is always empty. But the original dictionary has the rows in the List(Of String) that I read from the text file.
First Method that fills the dictionary:
Private Sub GetInfo()
Try
Dim sFileName As String = String.Empty
Dim sFileRows As List(Of String) = New List(Of String)
If IO.Directory.Exists("some directory")Then
Dim Files() As String = IO.Directory.GetFiles("directory and file type")
For Each File As String In Files
sFileName = Path.GetFileName(File)
Dim rdrRows As StreamReader = New StreamReader(File)
Dim sString As String
While rdrRows.Peek() >= 0
sString = rdrRows.ReadLine()
sFileRows.Add(sString)
End While
'Actually adding the info to the dictionary
dictDictionary.Add(sFileName, sFileRows)
rdrRows.Dispose()
sFileRows.Clear()
Next
End If
Catch ex As Exception
End Try
End Sub
Second Method to manipulate the order of elements in the List(Of String)
Private Sub ChangeStructure()
For Each kvp As KeyValuePair(Of String, List(Of String)) In dictDictionary
Dim rows As List(Of String) = kvp.Value
For Each item As String In rows
MessageBox.Show(item.ToString)
Next
Next
End Sub
There is nothing in the List(Of String) now but there was when it was filled in GetInfo()
Should be as easy as
Dim data = New Dictionary(Of String, List(Of String)) From _
{
{"Foo", New List(Of String) From {"1", "2", "3"}},
{"Bar", New List(Of String) From {"4", "5", "6"}}
}
For Each kvp in data
Console.WriteLine(kvp.Key & " says:")
For Each str in kvp.Value
Console.WriteLine(str)
Next
Next
For Each kvp As KeyValuePair(Of String, List(Of String)) In dictDictionary
Dim rows As List(Of String) = kvp.Value
If rows Is Nothing Then Continue
For Each item As String in rows
'...
Next item
Next kvp
You're are using kvp.Key, why are you not using kvp.Value?
For Each kvp As KeyValuePair(Of String, List(Of String)) In dictDictionary
Dim sKey As String = kvp.Key
Debug.Print("Filename: " & sKey)
Dim tempRows As List(Of String) = kvp.Value
Debug.Print("# of Lines: " & tempRows.Count)
Debug.Print("------------------------------")
For Each line As String In tempRows
Debug.Print(line)
Next
Debug.Print("------------------------------")
Debug.Print("")
Next
The problem is this line:
sFileRows.Clear()
List(Of String) is a reference type. After you fill the list and add it to the dictionary, you clear it, so it is empty when you try to access it later.
The solution is to create a new list each time in the loop. In other words, move this line:
Dim sFileRows As List(Of String) = New List(Of String)
inside the For loop and get rid of the call to .Clear()

value of type 'cfeedback' cannot be converted to 'system.collections.arraylist'

Firstly, i have a grdData at my main page. After choosing the data i want and went to another page using
Request.QueryString("id")
In that page i would like to make another grdData using the
Request.QueryString("id")
but came upon an error by
Value of type 'cfeedback' cannot be converted to 'system.collections.arraylist'
Below are my codes
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim objArrayList As New ArrayList
Dim objCDBFeedback As New CDBFeedback
Dim intGuestID2 As Integer
intGuestID2 = Request.QueryString("id")
objArrayList = objCDBFeedback.getFeedBack(intGuestID2)
grdResult.DataSource = objArrayList
grdResult.DataBind()
grdResult.HeaderRow.BackColor = Drawing.Color.AliceBlue
grdResult.RowStyle.BackColor = Drawing.Color.BlanchedAlmond
grdResult.AlternatingRowStyle.BackColor = Drawing.Color.LightSalmon
grdResult.Columns(0).Visible = True
End Sub
My Function
Public Function getFeedBack(ByVal pintGuestID1 As Integer) As CFeedback
Dim objCmd As New MySqlCommand
Dim objCn As New MySqlConnection(connectionString)
Dim objAdapter As New MySqlDataAdapter
Dim strSQL As String = ""
Dim objDs As New DataSet
Dim objDataRow As DataRow
strSQL = "SELECT * FROM tblFeedback WHERE strGuestCodeFB=" & pintGuestID1
objCmd.CommandText = strSQL
objCmd.Connection = objCn
objAdapter.SelectCommand = objCmd
objCn.Open()
objAdapter.Fill(objDs, "tblFeedback")
objDataRow = objDs.Tables("tblFeedback").Rows(0)
Dim objCFeedback As New CFeedback
objCFeedback.Feedback = objDataRow.Item("strGuestCompanyTI")
objCn.Close()
Return objCFeedback
End Function
My Class
Public Class CFeedback
Private strGuestCodeFB As Integer
Private strFeedBackFB As String
Public Property GuestId() As String
Get
Return strGuestCodeFB
End Get
Set(ByVal value As String)
strGuestCodeFB = value
End Set
End Property
Public Property Feedback() As String
Get
Return strFeedBackFB
End Get
Set(ByVal value As String)
strFeedBackFB = value
End Set
End Property
End Class
So is it possible to have a grdData base on querystring?
The very first thing that you need to do is edit your code behind and add the following two lines at the top:
Option Explicit On
Option Strict On
This will show you at least one error: assigning a type of CFeedback to a type of ArrayList.
You will need to determine what the appropriate resolution to this is, but I suspect that you want to return an ArrayList or generic List from GetFeedback instead of just the one item.
So, among other changes, you will want to change pageload to look something like:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim objCDBFeedback As New CDBFeedback
Dim intGuestID2 As Integer
intGuestID2 = CInt(Request.QueryString("id"))
Dim cValues As System.Collections.Generic.List(Of CFeedback)
cValues = objCDBFeedback.getFeedBack(intGuestID2)
grdResult.DataSource = cValues
grdResult.DataBind()
grdResult.HeaderRow.BackColor = Drawing.Color.AliceBlue
grdResult.RowStyle.BackColor = Drawing.Color.BlanchedAlmond
grdResult.AlternatingRowStyle.BackColor = Drawing.Color.LightSalmon
grdResult.Columns(0).Visible = True
grdResult.Visible = cValues.Count <> 0
End Sub
And the getFeeback method to look something like:
Public Function getFeedBack(ByVal pintGuestID1 As Integer) As System.Collections.Generic.List(Of CFeedback)
Dim cValues As New System.Collections.Generic.List(Of CFeedback)
Using objCn As New MySqlConnection(connectionString)
Using objCmd As New MySqlCommand
Dim strSQL As String = ""
strSQL = "SELECT * FROM tblFeedback WHERE strGuestCodeFB=" & pintGuestID1
objCmd.CommandText = strSQL
objCmd.Connection = objCn
objCn.Open()
Using oReader As MySqlDataReader = objCmd.ExecuteReader
Do While oReader.Read
Dim objCFeedback As New CFeedback
objCFeedback.Feedback = oReader.Item("strGuestCompanyTI")
cValues.Add(objCFeedback)
Loop
End Using
objCn.Close()
End Using
End Using
Return cValues
End Function