VB.NET DataTable - Getting the first "n" items of a column without using a loop - vb.net

I have a DataTable dtand need to store the first n items of a certain column in an integer array. I know it's easy to do this with a loop like this:
Dim array(n-1) As Integer
For i As Integer = 0 To n-1
array(i) = dt.Rows(i).Item("columName")
Next
Nonetheless, is there a more convenient way to store these items in the array?

"Without using a loop" is impossible since there is no magic way to retrieve items from a collection without looping it. However, maybe you think that LINQ does not use loops:
Dim columNameValues = From row In dt
Select row.Field(Of Int32)("columName")
Dim array As Int32() = columNameValues.ToArray()
Gets all values from all rows, if you want to get n values use Enumerable.Take:
Dim array As Int32() = columNameValues.Take(n).ToArray()
In VB.NET you can even use Take in a LINQ query:
Dim first10Values = From row In dt
Select row.Field(Of Int32)("columName")
Take 10
For what it's worth, as Barry has mentioned it is technically possible to get n items from a collection without using a loop, but see yourself:
Dim value1 As Int32 = dt.Rows(0).Field(Of Int32)("columName")
Dim value2 As Int32 = dt.Rows(1).Field(Of Int32)("columName")
Dim value3 As Int32 = dt.Rows(2).Field(Of Int32)("columName")
' ..... '
Dim value10 As Int32 = dt.Rows(9).Field(Of Int32)("columName")
You could add them to a List(Of Int32), but that's just for demonstration purposes anyway.

Related

2-D array from txt in VB.NET

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.

build an array of integers inside a for next loop vb.net

i got this far ... my data string, "num_str" contains a set of ~10 numbers, each separated by a comma. the last part of the string is a blank entry, so i use '.Trim' to avoid an error
Dim i As Integer
Dim m_data() As String
m_data = num_str.Split(",")
For i = 0 To UBound(m_data)
If m_data(i).Trim.Length > 0 Then
MsgBox(Convert.ToInt32(m_data(i).Trim))
End If
Next i
as you can see from the Msgbox, each of the numbers successfully pass through the loop.
where i am stuck is how to place all of the 'Convert.ToInt32(m_data(i).Trim)' numbers, which are now presumably integers, into an array.
how do i build an array of integers inside the For / Next loop so i can find MAX and MIN and LAST
TIA
You just need to initialize the array with the zero-based indexer. You can deduce it's initial size from the size of the string():
Dim m_data = num_str.Split({","c}, StringSplitOptions.RemoveEmptyEntries)
Dim intArray(m_data.Length) As Int32
For i = 0 To m_data.Length - 1
intArray(i) = Int32.Parse(m_data(i).Trim())
Next i
Note that i've also used the overload of String.Split which removes empty strings.
This way is more concise using the Select LINQ Operator.
Dim arrayOfInts = num_str.
Split({","c},
StringSplitOptions.RemoveEmptyEntries).
Select(Function(v) Int32.Parse(v.Trim()))
Dim minInt = arrayOfInts.Min()
Dim maxint = arrayOfInts.Max()

VisualBasic 2010 - merge 2 strings and read them as a variable

i have this code, and i want to access some variables.
Dim k1 as String = "Something"
Dim k2 as String = "Something"
... to k230
------------------Then i have this:
Dim rnd = New Random()
Dim nextValue = rnd.Next(230)
For i = 0 To 230
If nextValue = i Then
MsgBox('k+i') <--BUT READ THIS AS A VARIABLE.
End If
i = i + 1
Next
i readed some similar questions, but them doesn't apply to this case.
Consider using arrays here:
http://msdn.microsoft.com/en-us/library/vstudio/wak0wfyt.aspx
An array is a set of values that are logically related to each other,
such as the number of students in each grade in a grammar school.
By using an array, you can refer to these related values by the same
name, and use a number that’s called an index or subscript to tell
them apart. The individual values are called the elements of the
array. They’re contiguous from index 0 through the highest index
value.
Try using a Dictionary:
Dim k As New Dictionary(Of Integer, String)()
k.Add(1, "Something")
k.Add(2, "Something")
'... to 230
Messagebox.Show(k(i))

Find the maximum string in Combobox

I am trying to change combobox's DropDownWidth based on maximum string in Combobox's items.
The code below returns the maximum string length from all the items.
Dim maxStringLength As Integer = cboDt.AsEnumerable().
SelectMany(Function(row) row.ItemArray.OfType(Of String)()).
Max(Function(str) str.Length)
cboDt is the datatable attached to combobox.
I want to return the actual string.
For example if combobox items are:
"aaa"
"bbbb"
"ccccc"
My code returns maxStringLength = 5 (because 5 is the maximum number of characters of all items-here is ccccc)
I want code to retun "ccccc" (of course in a string variable)
Order the list by string-length descending, and then take the first result.
Dim maxStringLength As Integer =
cboDt.AsEnumerable().
SelectMany(Function(row) row.ItemArray.OfType(Of String)()).
OrderByDescending(Function(str) str.Length).
First() ' You can use FirstOrDefault here, if you are
' not certain there will be a result.
Assuming that the first column of the DataTable is displayed in the ComboBox:
Dim maxStringLength As Integer = cboDt.AsEnumerable().
Max(Function(r) r.Field(Of String)(0).Length)
Note that this assumes that this requires that this column is never null.
( I don't see a reason why you would measure the length of the (possibly available) other columns of the table when they aren't shown in the ComboBox at all. )
Update
Find the maximum string in Combobox
Now i got it, you want the string not the length:
Dim longestString = cboDt.AsEnumerable().
OrderByDescending(Function(r) r.Field(Of String)(0).Length).
First().Field(Of String)(0)
You can achieve this using linq and Finding the Index of maxStringLength = 5
Dim ls = comboBox4.Items.Cast(Of String)().ToList()
Dim index = ls.FindIndex(Function(c) c.ToString().Count() >= 5)
comboBox4.SelectedIndex = index
or using Max() Method
Dim ls = comboBox4.Items.Cast(Of String)().ToList()
Dim index = ls.Max()
comboBox4.Text = index

DataTable to ArrayList

I want to get value from datatable and then store it to the string() arraylist. datatable contain 3 column (columnA | columnB | columnC). I want to get all value from columnB and store it to arraylist.
I have try something like this
If myTableData.Rows.Count > 0 Then
For i As Integer = 0 To myTableData.Rows.Count - 1
Dim value() As String = myTableData.Rows(i)(1)
Next
End If
but when I compile that code, I got error message like this :
Unable to cast object of type 'System.String' to type 'System.String[]'
please help me.....
You could do that with LINQ:
Dim colBValues = (From row In myTableData Select colB = row(1).ToString).ToList
Or if you prefer the "old-school" way:
Dim colBValues = New List(Of String)
For Each row As DataRow In myTableData.Rows
colBValues.Add(row(1).ToString)
Next
I've used a List(Of String) because it's type-safe, therefore you don't need to cast the values everytime. That makes code more readable, more failsafe and faster.
If you need it as String-Array, you could simply use ToArray:
Dim colBValues = (From row In myTableData Select colB = row(1).ToString).ToArray
List(T)
LINQ
Dim a() As String
Dim total As Integer
'Count the number of rows
total = myTableData.Rows.Count - 1
ReDim a(0 To total)
For i = 0 To total
a(i) = myTableData.Rows(i)(1)
Next
This is really old question, but I'll provide one more variant of answer :
Dim value = myTableData.Rows.OfType(Of DataRow).Select(Function(x) x(1).ToString()).ToArray
So, if You have more than one column in Your DataTable You can use x(columnIndex) instead 1.