Building a multidimensional array in vb.net - vb.net

I'm trying to build up a multidimensional array which will hold two bits of info for each record in a database e.g. id, description.
This is what I am currently doing.
Dim mArray(,) As String
Dim i As Integer = 0
While cmdReader.Read()
mArray(i,0) = cmdReader.Item("id")
mArray(i,1) = cmdReader.Item("description")
i = i + 1
End While
The problem I have here is that it doesn't like the i in mArray(i,0). Anyone have any ideas about this? This is the error that is given Object reference not set to an instance of an object.
Thanks for any and all help.
Nalum

Why not rather make use of List Class and Dictionary Class
You can rather then create a List of Dictionaries, with the key and value both strings. The key can then represent your key (id and description in your example, and the value can be what ever was stored).
Something like
Dim values As New List(Of Dictionary(Of String, String))()
and then in the while loop something like
values.Add(New Dictionary(Of String, String)() From { _
{"id", cmdReader.Item("id")} _
})
values.Add(New Dictionary(Of String, String)() From { _
{"description", cmdReader.Item("description")} _
})
You could then use foreach
For Each value As Dictionary(Of String, String) In values
Dim id As String = value("id")
Dim description As String = value("description")
Next
Or a for
For i As Integer = 0 To values.Count - 1
Dim value As Dictionary(Of String, String) = values(i)
Dim id As String = value("id")
Dim description As String = value("description")
Next

Try this
Dim mArray(1,1) As String
Dim i As Integer = 0
While cmdReader.Read()
mArray(i,0) = cmdReader.Item("id")
mArray(i,1) = cmdReader.Item("description")
i = i + 1
ReDim Preserve mArray(i,1)
End While

The problem is that you are not initializing the array.
This should work, until i will not reach the limits set in the initialization.
Dim mArray(100,100) As String
Dim i As Integer = 0
While cmdReader.Read()
mArray(i,0) = cmdReader.Item("id")
mArray(i,1) = cmdReader.Item("description")
i = i + 1
End While
But if the array limits are not known I suggest to follow astander's suggestion.

This works for me:
Dim values As New List(Of Dictionary(Of String, String))()
values.Add(New Dictionary(Of String, String)() From {{"quarter", q1.ToString}, {"year", y1.ToString}})
values.Add(New Dictionary(Of String, String)() From {{"quarter", q2.ToString}, {"year", y2.ToString}})
values.Add(New Dictionary(Of String, String)() From {{"quarter", q3.ToString}, {"year", y3.ToString}})
values.Add(New Dictionary(Of String, String)() From {{"quarter", q4.ToString}, {"year", y4.ToString}})
For Each value As Dictionary(Of String, String) In values
Dim quarter As String = value("quarter")
Dim year As String = value("year")
Debug.Print(quarter & "/" & year)
Next

Correct it by
Dim mArray(,) As String = ""

Related

from list to string with formatting

i have a function getSelectedNumbers that take as input 3 list of number. after a manipulation i need to obtain a string in the format
"[1_3,10,20,30,500],[1_1,2],[]"
if the list is empty i need to have in the string the "[]" char
i wrote the below function but i need to manage the empty case.
Based on comment of Anu6is :
i was able to rewrite my code as below
'''vb
Public Function getSelectedNumbers() As String
Dim selectedNumbers1 As IList(Of Element) = repo.CanvasTerminalProduct.BoardDetails.Panel.pnlSuper3Panel1.Find(".//div[#class='selected']")
Dim selectedNumbers2 As IList(Of Element) = repo.CanvasTerminalProduct.BoardDetails.Panel.pnlSuper3Panel2.Find(".//div[#class='selected']")
Dim selectedNumbers3 As IList(Of Element) = repo.CanvasTerminalProduct.BoardDetails.Panel.pnlSuper3Panel3.Find(".//div[#class='selected']")
Dim list1 As New List(Of String)
Dim list2 As New List(Of String)
Dim list3 As New List(Of String)
For i As Integer = 0 To selectedNumbers1.Count -1
list1.Add(selectedNumbers1(i).GetAttributeValue("innerText").ToString)
Next i
For i As Integer = 0 To selectedNumbers2.Count -1
list2.Add(selectedNumbers2(i).GetAttributeValue("innerText").ToString)
Next i
For i As Integer = 0 To selectedNumbers3.Count -1
list3.Add(selectedNumbers3(i).GetAttributeValue("innerText").ToString)
Next i
'Create List of List
Dim selectedNumbersList As New List(Of List(Of String)) From {list1, list2, list3}
Dim builder As New StringBuilder 'Used to build the output
'Convert all the list in the correct string format using the join
For Each listX As List(Of String) In selectedNumbersList
builder.Append("[1_").Append(String.Join(",", listX)).Append("],") 'String.Join() give you a comma delmited string
Next
'Remove the last, and the [1_] that are not needed
Dim strSelectedNunmber As String = builder.ToString().TrimEnd(","c)
strSelectedNunmber = strSelectedNunmber.ToString().Replace("[1_]","[]")
Return str
End Function
'''
now my question is there is a better way to generate the list1 list2 list3 ?
This is assuming that Element is simply an Integer
Public Function getSelectedNumbers() As String
Dim selectedNumbers1 As New List(Of Integer) From {20, 30, 500, 10, 3} 'Unordered list
Dim selectedNumbers2 As New List(Of Integer) From {1, 2, 500} 'Ordered list
Dim selectedNumbers3 As New List(Of Integer) 'empty list
Dim selectedNumbersList As New List(Of List(Of Integer)) From {selectedNumbers1, selectedNumbers2, selectedNumbers3}
Dim builder As New StringBuilder 'Used to build the output
For Each list In selectedNumbersList
list.Sort() 'Sort your list
builder.Append("[").Append(String.Join(",", list)).Append("],") 'String.Join() give you a comma delmited string
Next
Return builder.ToString.TrimEnd(","c) 'Remove the final comma (,) and return the formatted string
End Function
[3,10,20,30,500],[1,2,500],[]
Does this work for you?
Dim selectedNumbers1 As New List(Of Integer) From {20, 30, 500, 10, 3}
Dim selectedNumbers2 As New List(Of Integer) From {1, 2, 500}
Dim selectedNumbers3 As New List(Of Integer)
'either make 3 loops or 1, but you have to make a list of lists first
Dim selectedNumbersList As New List(Of List(Of Integer)) From {selectedNumbers1, selectedNumbers2, selectedNumbers3}
For Each listX In selectedNumbersList
listX.Sort()
Dim ReturnString As String = "["
If listX.Count > 0 Then
For Each itemvalue In listX
ReturnString &= itemvalue & ","
Next
ReturnString = ReturnString.Remove(ReturnString.Length - 1)
End If
ReturnString &= "]"
Debug.Print(ReturnString)
Next
'[3,10,20,30,500]
'[1,2,500]
'[]

Add two string arrays to dictionary

I want to merge two string arrays in a Dictionary
I tried this:
Dim array1() As String = {"A","B"}
Dim array2() As String = {"a","b"}
Dim Dict As Dictionary(Of String, String)
For i = 0 To array1.Count() - 1
Dict.Add(array1(i), array2(i))
Next
but i got Null
Dim array1() As String = {"A","B"}
Dim array2() As String = {"a","b"}
Dim Dict As New Dictionary(Of String, String)
For i = 0 To array1.Count() - 1
Dict.Add(array1(i), array2(i))
Next
You don't New the Dictionary, i.e. no object to work with.

Error Returning A Dictionary From A Function

I have created a function to group data..
Private Function GroupData(ByVal validData As DataSet) As Dictionary(Of [String], List(Of DataRow))()
Dim serviceGroupDataset As DataSet = validData.Clone
Dim grouped As New Dictionary(Of [String], List(Of DataRow))()
Dim groupedRows As List(Of DataRow) = New List(Of DataRow)
For Each r As DataRow In validData.Tables("Detail").[Select]()
Dim key As [String] = r(AuthorizatonConstants.VA_Authorization_ID).ToString().Split("-"c)(0)
If Not grouped.TryGetValue(key, groupedRows) Then
groupedRows = New List(Of DataRow)()
grouped(key) = groupedRows
End If
groupedRows.Add(r)
Next
//COMPILE ERROR
Return grouped
End Function
I am getting a compile error when trying to return the dictionary..
Value of type 'System.Collections.Generic.Dictionary(Of String, System.Collections.Generic.List(Of System.Data.DataRow))' cannot be converted to '1-dimensional array of System.Collections.Generic.Dictionary(Of String, System.Collections.Generic.List(Of System.Data.DataRow))'.
How can I return the grouped dictionary from the function?
Your method signature is returning a Dictionary-array(because of the following ()), i assume you want to return a single dictionary.
You can use this Linq-To-DataTable approach which is more comprehensible:
Private Function GroupData(ByVal validData As DataSet) As Dictionary(Of String, List(Of DataRow))
Dim groups = From row In validData.Tables("Detail")
Let id = row.Field(Of String)(AuthorizatonConstants.VA_Authorization_ID).Split("-"c)(0)
Group row By id Into RowGroup = Group
Dim grouped As Dictionary(Of String, List(Of DataRow)) = groups.
ToDictionary(Function(grp) grp.id, Function(grp) grp.RowGroup.ToList())
Return grouped
End Function

How can i serialize and deserialize a dictionary in vb.net?

I am working with an application that needs to store large dictionaries of 40 000+ keys and values in a file, and then load them back into dictionaries on startup... Right now i am using a simple character separation with split and a for each loop on startup like:
key1=value1|key2=value2|key3=value3 etc...
however, i am looking for a more efficient way of serializing and deserializing the dictionaries... also with size of the serialized data in mind as there is quite a lot of entries.
You could make use of BinaryFormatter
On my mid end machine: save took: 390ms load took: 359ms data saved was about 1500kb
'save
Dim dict = New Dictionary(Of String, String)
For i = 1 To 40000
dict.Add("key" & i, "value" & i)
Next
Dim fs As IO.FileStream = New IO.FileStream("d:\test\test.bin", IO.FileMode.OpenOrCreate)
Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
bf.Serialize(fs, dict)
fs.Close()
'load
Dim fsRead As New IO.FileStream("d:\test\test.bin", IO.FileMode.Open)
Dim objTest As Dictionary(Of String, String) = bf.Deserialize(fsRead)
fsRead.Close()
This works well when using stacked dictionaries:
Dim DataDict as New Dictionary(Of String,Dictionary(Of String,String))
Here is a working example of embedded dictionaries being serialized for writing and reading:
Imports System.IO
Module Modules
Public Sub TestDict()
Dim DictsToSave As New Dictionary(Of String, Dictionary(Of String, String))
For DictsToHave = 1 To 10
Dim SingelDictData As New Dictionary(Of String, String)
For Values = 1 To 10000
SingelDictData.Add("Key " & Values.ToString(), "Value " & Values.ToString())
Next
DictsToSave.Add("Key " & DictsToHave.ToString(), SingelDictData)
Next
Dim WriteResult = WriteMultiSerializedDict("D:\TestDict.Bin", DictsToSave)
Dim ReadResult As Dictionary(Of String, Dictionary(Of String, String)) = ReadMultiSerializedDict("D:\TestDict.Bin")
End Sub
Public Function WriteMultiSerializedDict(ByVal FullPath As String, ByVal DataDict As Dictionary(Of String, Dictionary(Of String, String))) As Boolean
Try
Dim FileStream As IO.FileStream = New FileStream(FullPath, IO.FileMode.OpenOrCreate)
Dim BinFormatter As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
BinFormatter.Serialize(FileStream, DataDict)
FileStream.Close()
Return True
Catch ex As Exception
Return False
End Try
End Function
Public Function ReadMultiSerializedDict(ByVal FullPath As String) As Dictionary(Of String, Dictionary(Of String, String))
Try
Dim DataDict As New Dictionary(Of String, Dictionary(Of String, String))
Dim FileStream As IO.FileStream = New FileStream(FullPath, IO.FileMode.Open)
Dim BinFormatter As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
DataDict = BinFormatter.Deserialize(FileStream)
FileStream.Close()
Return DataDict
Catch ex As Exception
Return Nothing
End Try
End Function
On my mid end dev machine, this took about 260 ms for the write and 545 for the read, with a file that measured at 3.70 mb. Important note: If you change any of the dict's keys (not values), the load bombs! So, as a matter of programming, always assemble your dicts in the same order. I've used this approach before, using 5 100 key/value pairs in the sub dictionary's, without issue or problem.

How to add List as value in Hashtable

In vb.net If I have HashTable,key is integer and the value is a list of integers, how to append integers to the value of a given key,
I have tried it but each time I found the integer last added only, (the list only has the last item added).
Here is my code , where dt is DataTable object
Dim dt = report.getEvaluationReportByObjectiveGroupId(29)
Dim data As New Hashtable()
Dim dataEntry As DictionaryEntry
Dim res As String
For Each row As DataRow In dt.Rows
Dim strYear = row.Item("Year")
Dim strData = row.Item("EmpCount")
If data.ContainsKey(strYear) Then
Dim newCountArr As List(Of Int32) = DirectCast(data(strYear), List(Of Int32))
' newCountArr.AddRange(data(strYear))
newCountArr.Add(strData)
' data.Remove(strYear)
' data.Add(strYear, newCountArr)
Else
Dim countArr As New List(Of Integer)
countArr.Add(strData)
data.Add(strYear, countArr)
End If
' data.Add(strYear, strData)
Next row
I would suggest to use the strongly typed Dictionary(Of Int32, List(Of Int32)) instead, it works similar. But anyway, here's the HashTable approach:
Dim table = New Hashtable
Dim list = New List(Of Int32)
For i = 1 To 999
list.Add(i)
Next
table.Add(1, list)
' somewhere else you want to read the list for a given key (here 1) '
Dim list1 As List(Of Int32) = DirectCast(table(1), List(Of Int32))
list.Add(1000) ' add another integer to the end of the list '
' note: you don't need to add the list to the HashTable again '
Edit: Since you've posted your code, here's the corrected:
For Each row As DataRow In dt.Rows
Dim strYear = row.Field(Of Int32)("Year")
Dim strData = row.Field(Of Int32)("EmpCount")
Dim list As List(Of Int32)
If data.ContainsKey(strYear) Then
list = DirectCast(data(strYear), List(Of Int32))
Else
list = New List(Of Int32)
data.Add(strYear, list)
End If
list.Add(strData)
Next row