I have to read data from database to multidimensional array of unknown size.
Dim myarray As String()
Using reader = mcmd.ExecuteReader()
While (reader.Read())
myarray = TryCast(reader("mydataarray"), String())
End While
End Using
Here I got in myarray array of strings of last readed row only.
How to get that in 'myarray' will be readed data of all rows from sql result?
Here is code to do what I think you mean:
Using reader = mcmd.ExecuteReader()
Dim myOuterList as New List(of String())
While (reader.Read())
Dim myInnerList as New List(of String)
'For loop retrieves all columns of data as string
For i = 0 to reader.FieldCount - 1
myInnerList.Add(reader.GetString(i))
Next
myOuterList.Add(myInnerList.ToArray)
End While
End Using
dim myarray = myOuterList.ToArray
Resulting myarray will be of type String()() I.E. a two-dimensional array of strings.
Though this is possible, I would seriously consider using a typed solution as it will be much easier to understand code dealing with a list of a type than a two-dimensional array.
The typed version would be something like this:
Dim myList As List(Of myType) = reader.OfType(Of IDataRecord) _
.Select(Function(data) New myType _
With {.mydataarray = data.item("mydataarray")})
'Additionaly properties if needed.
Related
I am needing to create a code that is versatile enough where I can add more columns in the future with minimum reconstruction of my code. My current code does not allow me to travel through my file with my 2-D array. If I was to change MsgBox("map = "+ map(0,1) I can retrieve the value easily. Currently all I get in the code listed is 'System.IndexOutOfRangeException' and that Index was outside the bounds of the array. My current text file is 15 rows (down) and 2 columns (across) which puts it at a 14x1. they are also comma separated values.
Dim map(14,1) as string
Dim reader As IO.StreamReader
reader = IO.File.OpenText("C:\LocationOfTextFile")
Dim Linie As String, x,y As Integer
For x = 0 To 14
Linie = reader.ReadLine.Trim
For y = 0 To 1
map(x,y) = Split(Linie, ",")(y)
Next 'y
Next 'x
reader.Close()
MsgBox("map = " + map(y,x))``
Here's a generic way to look at reading the file:
Dim data As New List(Of List(Of String))
For Each line As String In IO.File.ReadAllLines("C:\LocationOfTextFile")
data.Add(New List(Of String)(line.Split(",")))
Next
Dim row As Integer = 1
Dim col As Integer = 10
Dim value As String = data(row)(col)
This is the method suggested by Microsoft. It is generic and will work on any properly formatted comma delimited file. It will also catch and display any errors found in the file.
Using MyReader As New Microsoft.VisualBasic.
FileIO.TextFieldParser(
"C:\LocationOfTextFile")
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
Dim currentField As String
For Each currentField In currentRow
MsgBox(currentField)
Next
Catch ex As Microsoft.VisualBasic.
FileIO.MalformedLineException
MsgBox("Line " & ex.Message &
"is not valid and will be skipped.")
End Try
End While
End Using
Essentially what you are asking is how can I take the contents of comma-separated values and convert this to a 2D array.
The easiest way, which is not necessarily the best way, is to return an IEnuemrable(Of IEnumerable(Of String)). The number of items will grow both vertically based on the number of lines and the number of items will grow horizontally based on the values split on a respective line by a comma.
Something along these lines:
Private Function GetMap(path As String) As IEnumerable(Of IEnumerable(Of String)
Dim map = New List(Of IEnumerable(Of String))()
Dim lines = IO.File.ReadAllLines(path)
For Each line In lines
Dim row = New List(Of String)()
Dim values = line.Split(","c)
row.AddRange(values)
map.Add(row)
Next
Return map
End Function
Now when you want to grab a specific cell using the (row, column) syntax, you could use:
Private _map As IEnumerable(Of IEnumerable(Of String))
Private Sub LoadMap()
_map = GetMap("C:/path-to-map")
End Sub
Private Function GetCell(row As Integer, column As Integer) As String
If (_map Is Nothing) Then
LoadMap()
End If
Return _map.ElementAt(row).ElementAt(column)
End Function
Here is an example: https://dotnetfiddle.net/ZmY5Ki
Keep in mind that there are some issues with this, for example:
What if you have commas in your cells?
What if you try to access a cell that doesn't exist?
These are considerations you need to make when implementing this in more detail.
You can consider the DataTable class for this. It uses much more memory than an array, but gives you a lot of versatility in adding columns, filtering, etc. You can also access columns by name rather than index.
You can bind to a DataGridView for visualizing the data.
It is something like an in-memory database.
This is much like #Idle_Mind's suggestion, but saves an array copy operation and at least one allocation per row by using an array, rather than a list, for the individual rows:
Dim data = File.ReadLines("C:\LocationOfTextFile").
Select(Function(ln) ln.Split(","c)).
ToList()
' Show last row and column:
Dim lastRow As Integer = data.Count - 1
Dim lastCol As Integer = data(row).Length - 1
MsgBox($"map = {data(lastRow)(lastCol)}")
Here, assuming Option Infer, the data variable will be a List(Of String())
As a step up from this, you could also define a class with fields corresponding to the expected CSV columns, and map the array elements to the class properties as another call to .Select() before calling .ToList().
But what I really recommend is getting a dedicated CSV parser from NuGet. While a given CSV source is usually consistent, more broadly the format is known for having a number of edge cases that can easily confound the Split() function. Therefore you tend to get better performance and consistency from a dedicated parser, and NuGet has several good options.
I try to copy all columns in my datagridview (DGView7) to my report viewer.
I used this code, but it didn't work
Dim myAL As New ArrayList()
Dim row As List(Of String)
For i As Integer = 0 To Basicfor.DGView7.RowCount() - 1
row = New List(Of String)
For j As Integer = 0 To Basicfor.DGView7.ColumnCount() - 1
row.Add(Basicfor.DGView7.Rows(i).Cells(j).ToString)
Next j
myAL.Add(row)
Next i
Dim Params(0) As ReportParameter
Params(0) = New ReportParameter("Ref", CType(myAL.ToArray(GetType(String)), String()))
Me.ReportViewer1.RefreshReport()
It shows an error. I tried to change to this code string() -> Single(), but single is not defined
Params(0) = New ReportParameter("Ref", CType(myAL.ToArray(GetType(String)), Single()))
Can anyone resolve this? Thanks in advance
You're calling
Params(0) = New ReportParameter("Ref", CType(myAL.ToArray(GetType(String)), String()))
And wanting to pass in an array of strings(). That's my assumption at least
However you're passing an array of list of strings.
Try
Dim myStrings = myAL.Cast(Of List(Of String)).SelectMany(Function(r) r).ToArray()
Needed code is something like this:
Dim myArray(0) As String
Dim ay As String = "ay"
myArr & ay(0) = "asd"
I've tried but did not worked
Dim classlist1(0) As String
Dim classlist2(0) As String
Dim classlist3(0) As String
Dim classlist4(0) As String
Dim count As Integer = 0
For _year As Integer = 1 To 4
("classlist" & _year)(count) = "hi"
count += 1
Next
Any time you see something like this:
Dim classlist1(0) As String
Dim classlist2(0) As String
Dim classlist3(0) As String
' etc.
It's an indication that you're using the wrong data structure. Instead of trying to dynamically build variable names (which isn't really possible in a static language, at least not without some really ugly reflection code with a high potential for runtime errors), just use a collection.
For example, if you want a collection of strings:
Dim classList As New List(Of String)()
And if you want a collection of collections of strings:
Dim classLists As New List(Of List(Of String))()
Then you can reference the nested lists within the parent list. So to add your first "year" of classes:
classLists.Add(new List(Of String))
And add a class to that year:
classLists(0).Add("some value")
As you can see, it starts to get a little difficult to keep track of the data structures. This is where creating custom types and structures becomes very useful. For example, rather than representing a "year" as a list of strings, create an actual Year class. That class can internally hold a list of strings, and other logic/data.
Try Dictionary<TKey, TValue> Class From MSDN.
Dim classLists As New Dictionary(Of String, String)()
'Add items with keys
For _year As Integer = 1 To 4
classLists.Add(String.Format("classlist{0}",_year), "hi")
Next
And you can get value by key later
Dim key As String = "classlist2"
Dim value As String = classLists(key)
I have a text file containing tab-seperated integers and doubles, e.g.:
5[TAB]0.3[TAB]2.9[TAB]61[TAB]110
8[TAB]1.1[TAB]5.2[TAB]13[TAB]45
1[TAB]0.8[TAB]1.4[TAB]28[TAB]33
...
What I need is a convenient way to access each line as a double array in VB.NET - so that the first array would be [5.0 0.3 2.9 61.0 110.0], the second array would be [8.0 1.1 5.2 13.0 45.0], and so on...
How can this be accomplished using the StreamReader?
If it's ok to use a list of lists instead of a list of arrays, you can just do this:
Private Function LoadFile(ByVal filePath As String) As List(Of List(Of Double))
Dim records As New List(Of List(Of Double))()
For Each line As String In File.ReadAllLines(filePath)
Dim values As New List(Of Double)()
For Each field As String In line.Split(New String() {ControlChars.Tab}, StringSplitOptions.None)
values.Add(Double.Parse(field))
Next
records.Add(values)
Next
Return records
End Function
Or, if it must be a list of arrays, you could do this:
Private Function LoadFileToArrays(ByVal filePath As String) As List(Of Double())
Dim records As New List(Of Double())()
For Each line As String In File.ReadAllLines(filePath)
Dim values As New List(Of Double)()
For Each field As String In line.Split(New String() {ControlChars.Tab}, StringSplitOptions.None)
values.Add(Double.Parse(field))
Next
records.Add(values.ToArray())
Next
Return records
End Function
If you need an array of arrays, you could just return records.ToArray(), instead, in that last example. I did not add any code to handle invalid or empty field values, because it wasn't clear, in your question, how you would want to handle those. So, you'll want to add code to handle that appropriately, otherwise, this code will throw an exception in such cases.
I've managed to make some single dimension array lists but I can't figure out a multi dimension arraylist.
Here's what I'm trying to do:
I have a database (mdb) with 5 columns that I want each row to be in an array list.
In PHP what I'd typically do is:
$array[$field1] = array($field2,$field3,$field4,$field5);
How I do the same in vb.net so anytime I need to fetch an item for a specific for the row1 I could call it?
For a single dimension I could do the following, but I can't figure out how to add more fields to a single array row:
Dim tmpArrayX As New ArrayList
tmpArrayX.Add(field(0))
tmpArrayX.Add(field(1))
etc...
If you want to use ArrayList, just make it's items contain other ArrayLists.
Or you could use normal arrays as:
Dim multiArray(2, 2) As String
multiArray(0, 0) = "item1InRow1"
multiArray(0, 1) = "item2InRow1"
multiArray(1, 0) = "item1InRow2"
multiArray(1, 1) = "item2InRow2"
Though my personal preference would be to use List as:
Dim multiList As New List(Of List(Of String))
multiList.Add(New List(Of String))
multiList.Add(New List(Of String))
multiList(0).Add("item1InRow1")
multiList(0).Add("item2InRow1")
multiList(1).Add("item1InRow2")
multiList(1).Add("item2InRow2")
Edit: How to find row:
Dim listIWant As List(Of String) = Nothing
For Each l As List(Of String) In multiList
If l.Contains("item1InRow2") Then
listIWant = l
Exit For
End If
Next
' This allows adding rows on the fly....Tested and it works!
Dim multiList As New List(Of List(Of String))
Dim ListRow As Integer = 0
For each record in some_source
dim Country as string = record.country 'from some source
dim Date as Date = record.Date 'from some source
dim Venue as string = record.Venue 'from some source
dim Attendance as string = record.Attendance 'from some source
multiList.Add(New List(Of String))
multiList(ListRow).Add(Country)
multiList(ListRow).Add(Date)
multiList(ListRow).Add(Venue)
multiList(ListRow).Add(Rating)
multiList(ListRow).Add(Attendance)
ListRow = ListRow + 1
next