Working from a previous question I asked (which was answered very well).. Ive come across another snag... In the following code
Public Sub Main()
Dim EntireFile As String
Dim oRead As System.IO.StreamReader
oRead = File.OpenText("testschedule.txt")
EntireFile = oRead.ReadToEnd
Dim table As New List(Of List(Of String))
' Process the file
For Each line As String In EntireFile.Split(Environment.NewLine)
Dim row As New List(Of String)
For Each value In line.Split(",")
row.Add(value)
Next
table.Add(row)
Next
' Display all contents of 5th column in the "table" using LINQ
Dim v = From c In table Where c(5) = ""
For Each x As List(Of String) In v
Console.WriteLine(x(0)) ' printing the 1st column only
Next
Console.WriteLine("Value of (2, 3): " + table(1)(2))
End Sub
`
The area where it says Dim v = From c In table Where c(5) = "" the blank quotations will only accept a specific number that its looking for in that column.
For Example:
Dim v = From c In table Where c(5) = "7" Will only show me any 7's in that column. Normally there will be many different values and I want it to print everything in that column, I just cant figure out the command to have it display everything in the selected column
Once again Many MANY Thanks!
If you want to show all rows (to be precise: items in the IEnumerable), just remove the Where condition
Dim v = From c In table
Just a note: table is not a very good name for your list, it leads the thought to SQL. This is just Linq2Objects and you don't query tables you query plain objects with a syntax very similar to Linq2SQL that in turn is heavily inspired by SQL.
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.
The below code I tried to sum up the string value with the list values, it happens, but other values are not shown in return. I need to sum the values and other value should be returned to the object using linq in vb.net.
My code:
Dim lstrTaxValue As String = "YQ$40"
Dim lstaValues As New List(Of String)
lstaValues.Add("YQ$10")
lstaValues.Add("TQ$3")
lstaValues.Add("PQ$8")
lstaValues.Add("YQ$10")
lstaValues.Add("TQ$3")
lstaValues.Add("AQ$5")
Dim lobjTValues = (From lstr In lstaValues
From lval In lstrTaxValue.Split(" ")
Where (lstr.Split("$")(0) = CStr(lval).Split("$")(0))
Select (CStr(lval).Split("$")(0) & "$" & (CDbl(CStr(lval).Split("$")(1)) + CDbl(lstr.Split("$")(1))))).ToList()
What am I doing wrong?
To quote Jon Skeet...
Change some value inside the List<T>
In comments...
Why do you want to use lambda expressions? The foreach code works fine and is simple. LINQ is for querying data, not mutating it. – Jon Skeet
Your objective does not seem to lend itself to Linq.
Private Sub OPCode()
Dim lstrTaxValue As String = "YQ$40"
Dim lstaValues As New List(Of String)
lstaValues.Add("YQ$10")
lstaValues.Add("TQ$3")
lstaValues.Add("PQ$8")
lstaValues.Add("YQ$10")
lstaValues.Add("TQ$3")
lstaValues.Add("AQ$5")
Dim TaxValue = lstrTaxValue.Split("$"c)
For i = 0 To lstaValues.Count - 1
If lstaValues(i).Split("$"c)(0) = TaxValue(0) Then
lstaValues(i) = TaxValue(0) & "$" & CStr(CDbl(lstaValues(i).Split("$"c)(1)) + CDbl(TaxValue(1)))
End If
Next
For Each s In lstaValues
Debug.Print(s)
Next
End Sub
Result:
YQ$50
TQ$3
PQ$8
YQ$50
TQ$3
AQ$5
I'm trying to create a vb.net application which saves the patient's history of illness to database. but i am stuck at how am i gonna save all listbox items to a single row (using comma as separator). I tried using this code but it only saves the last record:
Dim diagnosis As String
For i As Integer = 0 To txtDiagnosis.Items.Count - 1
diagnosis = String.Concat(txtDiagnosis.Items(i), ",")
Next
'Insert Query Here
I also wanted the last record not to have a comma after it. Thanks in advance
Use String.Join function. String.Join(Of T) Method
Dim diagnosis As String = String.Join(", ", txtDiagnosis.Items)
You can convert items to the collection of strings
Dim allDiagnosis = txtDiagnosis.Items.Select(Function(item) item.ToString())
Dim diagnosis As String = String.Join(", ", allDiagnosis)
For ListBox.Items you need explicitly cast collection to collection of objects
Dim allDiagnosis = txtDiagnosis.Items.
Cast(Of Object)().
Select(Function(item) item.ToString())
Dim diagnosis As String = String.Join(", ", allDiagnosis)
In VB.NET I'm trying to count through the value's in a list, until the value for "stock" in my DataTable, Boxes, is equal to the value in my list. When this occurs a row should be created in my new DataTable "output". I would then continue counting through the list looking for other matching instances to add into "output".
So far counting through the list and then within that count going through the datatable to match value's works wonderfully. The part where I'm getting hung up is when I try to take the matching row and put it into another table.
Dim output As DataTable
Dim jsonstringy As String = BoxComms.WebGet("http://foo.foo.foo") 'PULLS JSON STRING
Dim Boxes = Newtonsoft.Json.JsonConvert.DeserializeObject(Of DataTable)(jsonstring)
Dim MyString As String = TextBox1.Text 'MAKE STRING OF STOCK #'s FROM TEXTBOX
MyString = MyString.Replace(" ", "") 'GET RID OF SPACES
Dim MyArray() As String = MyString.Split(",") 'SEPERATE COMMA DELIMETED LIST
Dim MyList As List(Of String) = MyArray.ToList()
For Each value In MyList 'COUNT THROUGH LIST OF STOCK #'s
For Each row As DataRow In Boxes.Rows
If row("stock") = value Then 'IF STOCK # IS EQUAL TO ANY OF NUMBERS IN TEXTBOX
output.ImportRow(row) 'ADD ROW FROM DATATABLE Boxes to DATATABLE output
End If
Next row
Next
The solution was fairly simple, my DataTable needed a schema first. in order to copy the schema all I needed was to initialize the new table as a clone. to do so the code was as follows.
Dim output As DataTable = Boxes.Clone()
clone vs copy. copy get's the schema and data clone just gets the schema. then as I was parsing through the first table looking for matches I had to add the row to my new table with the following code.
output.Rows.Add(row.ItemArray)
the full code is as follows
Dim jsonstring As String = BoxComms.WebGet("https://foo.foo.foo")
Dim Boxes = Newtonsoft.Json.JsonConvert.DeserializeObject(Of DataTable)(jsonstring)
Dim output As DataTable = Boxes.Clone()
Dim MyString As String = TextBox1.Text
MyString = MyString.Replace(" ", "")
Dim MyArray() As String = MyString.Split(",")
Dim MyList As List(Of String) = MyArray.ToList()
For Each value In MyList
For Each row As DataRow In Boxes.Rows
If row("stock") = value Then
Console.WriteLine(row("stock"))
output.Rows.Add(row.ItemArray)
End If
Next row
Next
BoxControl.DataGridView1.DataSource = output
Me.Close()
End If
I need to store user input (entered from the console) to a Dataset in Visual Basic. Is this possible? I can't seem to find any information online about doing so. If anyone can point me in the right direction, that would be awesome!
EDIT: The columns in my table are FirstName, LastName, State, etc. in a table named Person.
The start of the application for the console: "Enter FirstName: ", then "EnterLastName: " then etc.
The values for the user inputs are stored in there specific variables eg. firstName, lastName, so I want to know how I can put those variables in a dataset.
Thank you.
Here is a short and basic example. Most likely it will not directly work for what you need as you will probably want to use a typed dataset among other things. Since your question does not specify a question regarding the code you may have already tried, this all I am going to provide.
Option Strict On
Module Module1
Sub Main()
Dim ds As DataSet = CreateNewDataSet()
Dim entries As New List(Of String())
For i = 1 To 3
Console.WriteLine($"Enter first column value for row {i.ToString}:")
Dim input1 As String = Console.ReadLine()
Console.WriteLine($"Enter second column value for row {i.ToString}:")
Dim input2 As String = Console.ReadLine()
entries.Add({input1, input2})
Next
entries.ForEach(Sub(x) ds.Tables(0).Rows.Add(x))
End Sub
Private Function CreateNewDataSet() As DataSet
Dim ds As New DataSet()
Dim dt As New DataTable()
Dim col1 As New DataColumn("Column1")
Dim col2 As New DataColumn("Column2")
dt.Columns.AddRange({col1, col2})
ds.Tables.Add(dt)
Return ds
End Function
End Module
If you don't know column names, you can use reflection to get names of properties of input objects. You can also use attributes to filter properties. Use DataTable.LoadDataRow method to load an array as row.
here is an example to how to do it dynamically:
Dim input As New List(Of Object)
For i = 0 To 5
Console.WriteLine("enter your first name and last name:")
input.Add(New With {.First = Console.ReadLine, .Last = Console.ReadLine})
Next
Dim myData As New DataSet
Dim table = myData.Tables.Add()
table.Columns.AddRange(input.First.GetType.GetProperties.Select(Function(p) New DataColumn(p.Name)).ToArray)
input.ForEach(Function(o) table.LoadDataRow(o.GetType.GetProperties.Select(Function(p) p.GetValue(o, Nothing)).ToArray, False))
For Each row In table.Rows
Console.WriteLine("first:{0} ,Last:{1}", row(0), row(1))
Next