Search delimited textfile in 2D array - vb.net

I have delimited a text file and put it into a 2D array. Then, I have tried to find out if the array contains the product ID (entered in a textbox). However, the code I have used to try to search the array and show the name does not work.
The textfile says:
1, Frances
2, Emma
Here is my code:
Public Class Form1
Dim filename As String
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
filename = "names.txt"
End Sub
Private Sub btnsearch_Click(sender As Object, e As EventArgs) Handles btnsearch.Click
filename = "names.txt"
FileOpen(1, filename, OpenMode.Input,,,)
Dim lines() As String = IO.File.ReadAllLines("names.txt")
Dim values(lines.Length - 1, 1) As String
For i As Integer = 0 To lines.Length - 1
Dim parts() As String = lines(i).Split(","c)
values(i, 0) = parts(0)
values(i, 1) = parts(1)
Next
Dim ID As String
ID = txtidsearch.Text
Dim line As String
Do While Not EOF(1)
line = LineInput(1)
If values().Contains(ID) Then
lblid.Text = line
Application.DoEvents()
GoTo line1
ElseIf EOF(1) = True
MsgBox("Not Found")
End If
Loop
line1:
FileClose(1)
End Sub
End Class
Thanks in advance

What I would do is create a class to hold your people. It would make it easier in the long run.
First create a Person class:
Imports System.Collections.ObjectModel
Public Class Person
Public Key As String
Public Sub New(ByVal id As Integer,
ByVal name As String,
ByVal form as String)
_id = id
_name = name
_form = form
End Sub
Private _id As Integer
Public ReadOnly Property Id() As Integer
Get
Return _id
End Get
End Property
Private _name As String
Public ReadOnly Property Name() As String
Get
Return _name
End Get
End Property
Private _form As String
Public ReadOnly Property Form() As String
Get
Return _form
End Get
End Property
End Class
Now create a People class which will be a collection to hold each Person:
Public Class People
Inherits KeyedCollection(Of String, Person)
Protected Overrides Function GetKeyForItem(ByVal item As Person) As String
Return item.Key
End Function
End Class
I would then change this bit of code:
Dim values(lines.Length - 1, 1) As String
For i As Integer = 0 To lines.Length - 1
Dim parts() As String = lines(i).Split(","c)
values(i, 0) = parts(0)
values(i, 1) = parts(1)
Next
To this:
Dim myPeople As New People
For i As Integer = 0 To lines.Length - 1
Dim parts() As String = lines(i).Split(","c)
myPeople.Add(New Person(parts(0), parts(1), parts(2)))
Next
Note that I am adding a new Person class to the People collection class.
And I would replace this code:
Dim line As String
Do While Not EOF(1)
line = LineInput(1)
If values().Contains(ID) Then
lblid.Text = line
Application.DoEvents()
GoTo line1
ElseIf EOF(1) = True
MsgBox("Not Found")
End If
Loop
line1:
With this:
Dim filteredLines = From people In myPeople
Where people.Id = ID
Select people
If filteredLines IsNot Nothing AndAlso filteredLines.Count = 1 Then
Label1.Text = filteredLines(0).Name
End If
This last bit of code is LINQ:
General-purpose query facilities added to the .NET Framework apply to all sources of information, not just relational or XML data. This facility is called .NET Language-Integrated Query (LINQ).
Using LINQ we can query the People collection class like we would a table on a database using similar syntax. Here I am selecting all of the People where the ID matches. I then check to ensure that filteredLines actually has a Person before assigning the value.

Related

find in a text file all rows with a specific value and display them in the datagridview

Good day!
There is a .csv text file in the following format:
Fred Smith
f.smith
engineer
21.12.2021
Ben Taylor
b.taylor
programmer
23.12.2021
Bill Davis
b.davis
programmer
19.12.2021
Steve Harris
s.harris
engineer
23.12.2021
Tom Walker
t.walker
engineer
23.12.2021
with the following code I display data from a text file into a DataGridView:
Dim list() As String = IO.File.ReadAllLines("D:\UserList.csv", System.Text.Encoding.Default)
For i = 0 To UBound(list)
DataGridView1.Rows.Add()
Dim data() As String = Split(list(i), "|")
For j = 0 To UBound(data) - 1
DataGridView1.Item(j, i).Value = data(j)
Next
Next
Tell me how you can display in the datagridview from a text file only those employees where a certain date is indicated in the line of the text file?
For instance:
Specified the date - 23.12.2021
In the DataGridView I want the following result to be displayed:
Ben Taylor
b.taylor
programmer
23.12.2021
Steve Harris
s.harris
engineer
23.12.2021
Tom Walker
t.walker
engineer
23.12.2021
Tell me how you can make such a selection before displaying data from a text file in the DataGridView?
However, do not delete these lines in the text file.
For j = 0 To UBound(data)-1
loop run before Date of joining column so that data not add to grid so i removed -1.
Actual problem for the new row should specify the row and column number as below code.
Dim list() As String = IO.File.ReadAllLines("D:\UserList.csv", System.Text.Encoding.Default)
For i = 0 To UBound(list)
DataGridView1.Rows.Add()
Dim data() As String = Split(list(i), "|")
For j = 0 To UBound(data)
'DataGridView1.Item(j, i).Value = data(j)
DataGridView1.Rows(i).Cells(j).Value = data(j)
Next
Next
There are several ways available. If you put the data into something which implements the IBindingListView interface such as a DataTable then you could use the Filter property. Documentation for that: BindingSource.Filter Property
Or, as I show here, you can use a List and use LINQ to create the filter, like this:
Imports System.IO
Public Class Form1
Dim userData As List(Of User) = Nothing
Dim inputDateFormat As String = "dd.MM.yyyy"
Dim displayDateFormat As String = "dd.MM.yyyy"
Public Class User
Property Name As String
Property Email As String
Property Title As String
Property MagicDate As DateTime
Sub New(name As String, email As String, title As String, magicDate As DateTime)
Me.Name = name
Me.Email = email
Me.Title = title
Me.MagicDate = magicDate
End Sub
End Class
Sub LoadData(src As String)
userData = New List(Of User)
For Each a In File.ReadLines(src)
Dim parts = a.Split("|"c)
If parts.Count = 4 Then
Dim md = DateTime.ParseExact(parts(3), inputDateFormat, Nothing)
Dim u = New User(parts(0), parts(1), parts(2), md)
userData.Add(u)
End If
Next
End Sub
Sub ShowData()
' show all the data
ShowData(Nothing)
End Sub
Sub ShowData(selectedDate? As DateTime)
If userData Is Nothing Then
Exit Sub
End If
Dim bs As New BindingSource
If selectedDate.HasValue Then
' select only the data with the desired date
bs.DataSource = userData.Where(Function(u) u.MagicDate = selectedDate.Value)
Else
' show all the data
bs.DataSource = userData
End If
DataGridView1.DataSource = bs
DataGridView1.Columns("MagicDate").DefaultCellStyle.Format = displayDateFormat
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LoadData("C:\temp\UserList.csv")
ShowData(New Date(2021, 12, 23))
End Sub
End Class
To get:
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim pattern As String = "23.12.2021"
Dim Path As String = "D:\UserList.csv"
Dim _row As String
Dim separator As Char = "|"
For Each _row In File.ReadAllLines(Path, Encoding.Default)
If _row.Contains(pattern) Then
DataGridView1.Rows.Add(_row.Split(separator))
End If
Next _row
End Sub
Why not do something like:
Dim list() As String = IO.File.ReadAllLines("D:\UserList.csv", System.Text.Encoding.Default)
Dim ub as Integer
For i = 0 To UBound(list)
Dim data() As String = Split(list(i), "|")
ub = UBound(data)
If data(ub) = "23.12.2021" Then
DataGridView1.Rows.Add()
For j = 0 To ub - 1
DataGridView1.Item(j, i).Value = data(j)
Next
End If
Next
Using the "User" class that Andrew Morton created:
Dim fileName = "C:\Bin\myFile.csv"
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim filterDate = Date.Parse("23.12.2021")
SetDataSource(filterDate)
End Sub
Private Sub SetDataSource(dateStamp As Date)
Dim data = File.ReadAllLines(fileName).Skip(1).
Select(Function(line) line.Split(",")).
Select(Function(x) New User(x)).
Where(Function(x) x.MagicDate = dateStamp)
DataGridView1.DataSource = data.ToList()
End Sub
Public Class User
Public Sub New(x() As String)
Name = x.ElementAt(0)
Email = x.ElementAt(1)
Title = x.ElementAt(2)
MagicDate = x.ElementAt(3)
End Sub
Property Name As String
Property Email As String
Property Title As String
Property MagicDate As DateTime
End Class
I added the Skip(1) in the LINQ so it ignores the header row. This can be removed if no header is present.

VB.NET Group by two columns and write results to an array

I need to group csv data to new csv by column values. I can do it by only one column, but unfortunately it is not enough, because I got duplicates and not achieve my goal. Here is my csv example, there is about 50 columns and last here is column(29) in my input csv:
603;10453;2.12.2020;88,69
603;10453;2.12.2020;88,69
603;10453;4.12.2020;72,69
605;10441;3.12.2020;39,51
605;10441;8.12.2020;25,85
605;10441;9.12.2020;52,91
605;10441;10.12.2020;66,31
605;10441;10.12.2020;66,31
606;10453;11.12.2020;72,69
606;10453;11.12.2020;72,69
607;11202;1.12.2020;250,98
607;11202;1.12.2020;250,98
607;11202;1.12.2020;250,98
607;11202;1.12.2020;250,98
607;11202;1.12.2020;250,98
607;11202;2.12.2020;274,02
607;11202;2.12.2020;274,02
607;11202;2.12.2020;274,02
607;11202;2.12.2020;274,02
607;11202;2.12.2020;274,02
607;11202;2.12.2020;274,02
607;11202;3.12.2020;165,29
607;11202;3.12.2020;165,29
607;11202;3.12.2020;165,29
607;11202;3.12.2020;165,29
607;11202;4.12.2020;75,87
607;11202;5.12.2020;123,24
607;11202;5.12.2020;123,24
607;11202;5.12.2020;123,24
607;11202;7.12.2020;88,69
607;11202;7.12.2020;88,69
And here is my code, where I group values by last column:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim inputFile = "input.csv"
Dim outputFile = "output.csv"
IO.File.WriteAllLines(outputFile, IO.File.ReadLines(inputFile).
Select(Function(x) x.Split(";"c)).
GroupBy(Function(x) {x(0), x(3)}).
Select(Function(x)
Return String.Format(
"{0};{1};{2};{3}",
x.Select(Function(y) y(0)).First,
x.Select(Function(y) y(1)).First,
x.Select(Function(y) y(2)).First,
x.Select(Function(y) y(3)).First)
End Function).ToArray)
End Sub
As you can see in the last column duplicate values and I need group this file by two keys, one of them column(0) or column(1) values and second one is column(3). But I can't figure out how I can I do it with my code.
Desiret outout file have to looks like this:
603;10453;2.12.2020;88,69
603;10453;4.12.2020;72,69
605;10441;3.12.2020;39,51
605;10441;8.12.2020;25,85
605;10441;9.12.2020;52,91
605;10441;10.12.2020;66,31
606;10453;11.12.2020;72,69
607;11202;1.12.2020;250,98
607;11202;2.12.2020;274,02
607;11202;3.12.2020;165,29
607;11202;4.12.2020;75,87
607;11202;5.12.2020;123,24
607;11202;7.12.2020;88,69
Usualy I have to remove duplicates if column(0) and column(2) if they has match.
Thanks for help!
I would use an object oriented approach. Make a wrapper object around each line that does the parsing and provides properties for each value, and then group the result as desired (I choose again the object oriented approach with an equality comparer and distinct).
As I don't know the meaning of the columns I simply assumed something: OrderNo, CustomerNo, OrderDate and Value.
Here's the code for the wrapper class:
Private Class Record
'Constructors
Public Sub New(lineNo As Int32, line As String)
Const expectedColumnCount As Int32 = 4
Const delimiter As String = ";"
If (lineNo < 1) Then Throw New ArgumentOutOfRangeException(NameOf(lineNo), lineNo, "The line number must be positive!")
If (line Is Nothing) Then Throw New ArgumentNullException(NameOf(line))
Dim tokens As String() = Split(line, delimiter, expectedColumnCount + 1, CompareMethod.Binary)
If (tokens.Length <> expectedColumnCount) Then Throw New ArgumentException($"Line {lineNo}: Invalid data row! {expectedColumnCount} '{delimiter}'-delimitered columns expected.")
Me.Tokens = tokens
End Sub
'Public Properties
Public ReadOnly Property OrderNo As String
Get
Return Tokens(0)
End Get
End Property
Public ReadOnly Property CustomerNo As String
Get
Return Tokens(1)
End Get
End Property
Public ReadOnly Property OrderDate As String
Get
Return Tokens(2)
End Get
End Property
Public ReadOnly Property Value As String
Get
Return Tokens(3)
End Get
End Property
'Private Properties
Private ReadOnly Property Tokens As String()
End Class
And this is the comparer that does the grouping:
Private Class RecordComparer
Implements IEqualityComparer(Of Record)
Private Sub New()
End Sub
Public Shared ReadOnly Property Singleton As New RecordComparer()
Public Function Equals(x As Record, y As Record) As Boolean Implements IEqualityComparer(Of Record).Equals
If (Object.ReferenceEquals(x, y)) Then Return True
If (x Is Nothing) OrElse (y Is Nothing) Then Return False
Return Comparer.Equals(x.OrderNo, y.OrderNo) AndAlso Comparer.Equals(x.CustomerNo, y.CustomerNo) AndAlso Comparer.Equals(x.Value, y.Value)
End Function
Public Function GetHashCode(obj As Record) As Integer Implements IEqualityComparer(Of Record).GetHashCode
If (obj Is Nothing) Then Return 42
Return Comparer.GetHashCode(obj.OrderNo) Xor Comparer.GetHashCode(obj.CustomerNo) Xor Comparer.GetHashCode(obj.Value)
End Function
Private Shared ReadOnly Comparer As IEqualityComparer(Of String) = StringComparer.Ordinal
End Class
and finally the usage:
'Convert input lines to simple objects
Dim i As Int32 = 1
Dim dataRows As New List(Of Record)()
For Each line As String In File.ReadLines(inputFile)
Dim data As New Record(i, line)
dataRows.Add(data)
i += 1
Next
'Group by the 3 columns (the DateTime is kind of random, no guarantee which object wins)
Dim consolidatedRows As IEnumerable(Of Record) = dataRows.Distinct(SimpleInputDataComparer.Singleton)
'Convert and export lines
Dim outputLines As IEnumerable(Of String) = consolidatedRows.Select(Function(e) $"{e.OrderNo};{e.CustomerNo};{e.OrderDate};{e.Value}")
File.WriteAllLines(outputFile, outputLines)
I got it work. For my goal I used Christoph example. Finaly my code looks like this:
Public Class TempClass
Public Property ID As String
Public Property day As String
Public Property OriginalStr As String
End Class
Public Class TempIDComparer
Implements IEqualityComparer(Of TempClass)
Private Function IEqualityComparer_Equals(x As TempClass, y As TempClass) As Boolean Implements IEqualityComparer(Of TempClass).Equals
If ReferenceEquals(x, y) Then
Return True
End If
If ReferenceEquals(x, Nothing) OrElse ReferenceEquals(y, Nothing) Then
Return False
End If
Return x.ID = y.ID AndAlso x.day = y.day
End Function
Private Function IEqualityComparer_GetHashCode(obj As TempClass) As Integer Implements IEqualityComparer(Of TempClass).GetHashCode
If obj Is Nothing Then Return 0
Return obj.ID.GetHashCode()
End Function
End Class
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim inputFile = "input.csv"
Dim outputFile = "output.csv"
Dim list As List(Of TempClass) = New List(Of TempClass)()
Dim ls As List(Of String()) = New List(Of String())()
Dim fileReader As StreamReader = New StreamReader(inputFile)
Dim strLine As String = ""
While strLine IsNot Nothing
strLine = fileReader.ReadLine()
If strLine IsNot Nothing AndAlso strLine.Length > 0 Then
Dim t As TempClass = New TempClass() With {
.ID = strLine.Split(";"c)(0),
.day = strLine.Split(";"c)(3),
.OriginalStr = strLine
}
list.Add(t)
End If
End While
fileReader.Close()
Dim tempList = list.Distinct(New TempIDComparer())
Dim fileWriter As StreamWriter = New StreamWriter(outputFile, False, System.Text.Encoding.Default)
For Each item In tempList.ToList()
fileWriter.WriteLine(item.OriginalStr)
Next
fileWriter.Flush()
fileWriter.Close()
End Sub

How to fill a datagridview with objects of a class

Okay so I think I've confused myself. I'm working on a class inventory database. My plan is to have a person enter their information and a book's info into the textboxes, and I want that informationan to be placed into the lstbox (basically saying who is now renting this book). I also have a Datagridview where I want my txtfile to open up in and display the books, but only the objects that are in my txtfile (Title, Author, ISBN, YearPublishished). I tried to do it with a query but it doesn't seem to be working.
I have a few errors that I need help with
When I start the application and click on display books. My OFD opens and I click the txtfile I need, but it doesnt display to my DataGridView properly. IT only shows numbers going down the columns.
We had to use objects of classes, and I just want to know if Im using them correctly. This is my first time doing this so any help would be appreciated.
I've attached a picture of my Application
Okay so this what I have so far:
Public Class Library
Implements IComparable
'Private Instance Variables - Always declared as Private
Private m_Title As String
Private m_Author As String
Private m_ISBN As String
Private m_YearPublished As Date
Private m_DateRented As Date 'use maskedtxtbox for dates and phone number
Private m_DueDate As Date
Private m_Name As String
Private m_Email As String
Private m_PhoneNumber As String
Private Shared LibraryCount As Integer
'Property Blocks for each Private Instance Variable
Public Property Title() As String
Get
Return m_Title
End Get
Set(value As String)
m_Title = value
End Set
End Property
Public Property Author() As String
Get
Return m_Author
End Get
Set(value As String)
m_Author = value
End Set
End Property
Public Property ISBN As String
Get
Return m_ISBN
End Get
Set(value As String)
m_ISBN = value
End Set
End Property
Public Property YearPublished As Date
Get
Return m_YearPublished
End Get
Set(value As Date)
m_YearPublished = value
End Set
End Property
Public Property DateRented As Date
Get
Return m_DateRented
End Get
Set(value As Date)
m_DateRented = value
End Set
End Property
Public Property DueDate As Date
Get
Return m_DueDate
End Get
Set(value As Date)
m_DueDate = value
End Set
End Property
Public Property Name As String
Get
Return m_Name
End Get
Set(value As String)
m_Name = value
End Set
End Property
Public Property Email As String
Get
Return m_Email
End Get
Set(value As String)
m_Email = value
End Set
End Property
Public Property PhoneNumber As String
Get
Return m_PhoneNumber
End Get
Set(value As String)
m_PhoneNumber = value
End Set
End Property
Public Sub New()
m_Title = ("")
m_Author = ""
m_ISBN = ""
m_DateRented = ""
m_DueDate = ""
m_Name = ""
m_Email = ""
m_PhoneNumber = 0
LibraryCount += 1
End Sub
'Overloaded /Parameterized Constructors
Public Sub New(ByVal p_Title As String, ByVal p_Author As String, ByVal p_ISBN As String, ByVal p_YearPublished As Date,
ByVal p_DateRented As Date, ByVal p_DueDate As Date, ByVal p_Name As String, ByVal p_Email As String, ByVal p_PhoneNumber As String)
m_Title = p_Title
m_Author = p_Author
m_ISBN = p_ISBN
m_YearPublished = p_YearPublished
m_DateRented = p_DateRented
m_DueDate = p_DueDate
m_Name = p_Name
m_Email = p_Email
m_PhoneNumber = p_PhoneNumber
LibraryCount += 1
End Sub
'QUESTION? How would I calculate when the books is due
' Public Function CalcDueDate() As String 'person gets charged if they are late returning the book
' If m_DateRented.Date > m_DueDate.Date Then
'm_DueDate = m_DateRented + 10
'MessageBox.Show("You will be charged with a late of .50 cents")
'End If
'End Function
Public Overrides Function ToString() As String
Return "The user rented a book on" & DateRented & " it will be due on" & DueDate
End Function
Public Function CalcDueDate(ByVal p_DueDate As Date) As Date
Return p_DueDate
End Function
Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo
Throw New NotImplementedException()
Return m_YearPublished.CompareTo(CType(obj, Library).m_YearPublished)
End Function
Public Overrides Function Equals(obj As Object) As Boolean
'create a library object from the paramer - check to see if it exist
Dim libraryobj As Library = TryCast(obj, Library)
If libraryobj Is Nothing Then
Return False
Else
'code for the comparison based on m_yearpublished
Return m_YearPublished.Equals(libraryobj.m_YearPublished)
End If
End Function
End Class
End Class
Public Class Project1Data
'create counter variable for the array
Dim counter As Integer = 0
'create an array of objects
Private books(12) As Library
'Collection List
Dim mybooklist As New List(Of Library)
Dim abook As Library
Private Sub btnDisplayBooks_Click(sender As Object, e As EventArgs) Handles btnDisplayBooks.Click
Dim textfile As String
OpenFileDialog1.ShowDialog()
textfile = OpenFileDialog1.FileName
DGVbooks.DataSource = IO.File.ReadAllLines("LibraryDatabase")
End Sub
Public Sub Data()
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
'The Btn_Add method creates a Renter and book and adds it to the collectio
'validate input data
If ValidateData() = -1 Then
Exit Sub
End If
'use valid input to create an object of the class by calling overloaded constructor
Dim bookk As New Library(txtbooktitle.Text, txtbookauthor.Text, txtISBN.Text, CDate(txtyearpublished.Text),
CDate(txtdaterented.Text), CDate(txtduedate.Text), txtname.Text, txtemail.Text, (txtphonenunber.Text))
'error check that the array is not full
If counter >= books.Length Then
ReDim Preserve books(counter + 1)
End If
'add book to the array
books(counter) = bookk
'add book to the list
mybooklist.Add(bookk)
'increment counter
counter = counter + 1
'Notify user that the rental has been recorder
MessageBox.Show("Rental recorded")
lstbooksoutput.DataSource = Nothing
lstbooksoutput.DataSource = books
End Sub
Private Sub Project1Data_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim lines() As String = IO.File.ReadAllLines("LibraryDatabase")
'In the DGV I just want to display the title, author, isbn, and year published
' In the lstbox the user name, email, and phone number will be displayed
'When a user enters a new book it adds itself to the DGV
Dim query = From abook In books
Select abook.Title, abook.Author, abook.ISBN, abook.YearPublished
Order By abook.YearPublished Ascending
DGVbooks.DataSource = query.ToList()
Okay here is where I created an objectof the class using an overload constructor, and I thought I sent it it to the datagridview but its not showing.
'Populate a list with Library objects
With mybooklist
.Add(New Library("Innoncent Injustice(A Chance Reddick Thriller Book 1), David Archer,B07D6442LM", 2018))
.Add(New Library("A Breath Of Witchy Air(A Wicked Witches Of the Midwest Mystery), Amanda M Lee, B07CRLRGXH", 2018))
.Add(New Library("Booke Of the Hidden, Jeri Westerson, 978 - 1635760507", 2017))
.Add(New Library("Wolves Of Wisteria(Wisteria Witches Mystery), Angela Pepper,978-1719549591", 2018))
.Add(New Library("Soul Render(Soul Stones Book 1), TL Branson,978-1980871392", 2018))
.Add(New Library("A Thrift Shop Murder(Cats And Ghosts And Avocado Toasts Book 1), Stanford Pritchard,978-1773480114", 2018))
.Add(New Library("Cathadeus, Jeff J Peters,B077ZNHY7T", 2017))
.Add(New Library("Clockwork Alchemist (Thief's Apprenctice Series Book 1), Sara C. Roethle,B01MG26KNA", 2016))
.Add(New Library("Air Awakens Series, Elise Kova,B01N4A2TK5", 2016))
.Add(New Library("Keeper of the Dragons The Prince Returns (Keeper of Dragons Book 1), J.A Cullican,B01FYL5BD0", 2016))
.Add(New Library("Nightblade A Book of UnderRealm, Garrett Robinson,978-1941076309", 2014))
.Add(New Library("Crazy Rich Asians, Kevin Kwan,B00AP2VQEM", 2013))
.Add(New Library("Poison Princess (The Arcana Chronicles Book 1), Kresley Cole,978-1442436640", 2012))
End With
DGVbooks.DataSource = query.ToList
DGVbooks.Columns("Title").HeaderText = "Title"
DGVbooks.Columns("Author").HeaderText = "Author"
DGVbooks.Columns("ISBN").HeaderText = "ISBN"
DGVbooks.Columns("Year Publsihed").HeaderText = "Year Published"
DGVbooks.DataSource = mybooklist
End Sub
Function ValidateData() As Integer
'This validates the data in all of the textboxes
'Invalid data returns a -1, else 1
If txtbooktitle.Text = "" Then
MessageBox.Show("Please enter a Book Title")
Return -1
ElseIf txtbookauthor.Text = "" Then
MessageBox.Show("Please enter a Book Title")
Return -1
ElseIf txtdaterented.Text = "" Or IsNumeric(txtdaterented.Text) = False Then
MessageBox.Show("Please enter a valid date")
Return -1
ElseIf txtduedate.Text = "" Or IsNumeric(txtduedate.Text) = False Then
MessageBox.Show("Please enter a valid date")
Return -1
ElseIf txtyearpublished.Text = "" Or IsNumeric(txtyearpublished.Text) = False Then
MessageBox.Show("Please enter a valid date")
Return -1
ElseIf txtname.Text = "" Then
MessageBox.Show("Please enter a name")
Return -1
ElseIf txtemail.Text = "" Then
MessageBox.Show("Please enter a valid email")
Return -1
ElseIf txtphonenunber.Text = "" Or IsNumeric(txtphonenunber.Text) = False Then
MessageBox.Show("Please enter a valid phone number")
Return -1
Else
Return 1
End If
End Function
Private Sub lstbooksoutput_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstbooksoutput.SelectedIndexChanged
If lstbooksoutput.SelectedIndex > -1 Then
Dim intbook As Integer = lstbooksoutput.SelectedIndex
'get information for that user in the array
MessageBox.Show(books(intbook).Name & " has rented" & books(intbook).Title & ". The book will be due on " & books(intbook).DueDate)
End If
End Sub
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
'clear the textboxes
txtbooktitle.Clear()
txtbookauthor.Clear()
txtISBN.Clear()
txtdaterented.Clear()
txtduedate.Clear()
txtyearpublished.Clear()
txtname.Clear()
txtemail.Clear()
txtphonenunber.Clear()
'reset focus to title box
txtbooktitle.Focus()
End Sub
End Class
enter image description here
Ok Sydney, let's get this thing working!
Either you have seriously ignored your studies or your instructor
has left you to flounder; in which case you should notify your
college that you are not getting what you are paying for.
Your object contains too much data. You need a book object, a customer object and a rental object. Suppose the library director
wants a list of all your clients. In your model you would have each
client listed many times and it would be a mess to get the director
his list.
Use Automatic Properties if you can. I think they are available in VS 2015. You only need to write Public Property Title as String
and the wonderful vb compiler will write the get, set, and the
private field for you in the Itermedite Language code. (You won't
see it in your source code but it is there)
Now your text file. One line per book. Each property of the book should be separated by a character that does not appear elsewhere in
the file. How about the pipe character (|) (the uppercase backslash)
So a line in your file would look like... 1|Innoncent Injustice(A
Chance Reddick Thriller Book 1)|David Archer|B07D6442LM|2018 Notice
I have added another field, the BookID
I haven't included the default constructor (the one with no parameters). This forces any code creating a book object to provide
values for all parameters even if it is only "".
Public Class Book
Public Property BookID As Integer
Public Property Title As String
Public Property Author As String
Public Property ISBN As String
Public Property YearPublished As Integer
Public Sub New(id As Integer, bTitle As String, bAuthor As String, bISBN As String, bPublished As Integer)
BookID = id
Title = bTitle
Author = bAuthor
ISBN = bISBN
YearPublished = bPublished
End Sub
End Class
Public Class Project1Data
Private lstBooks As New List(Of Book)
Private Sub Project1Data_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim textfile As String
OpenFileDialog1.ShowDialog()
textfile = OpenFileDialog1.FileName
Dim lines() As String = IO.File.ReadAllLines(textfile)
For Each line As String In lines
Dim fields() As String = line.Split("|"c) 'the little c after "|" indicates that this is a char
'String.Split takes a char
Dim b As New Book(CInt(fields(0)), fields(1), fields(2), fields(3), CInt(fields(4)))
lstBooks.Add(b)
Next
DataGridView1.DataSource = lstBooks
End Sub
End Class

Multiple Search Criteria (VB.NET)

So my problem is:
I have a List of a custom Type {Id as Integer, Tag() as String},
and i want to perform a multiple-criteria search on it; eg:
SearchTags={"Document","HelloWorld"}
Results of the Search will be placed a ListBox (ListBox1) in this format:
resultItem.id & " - " & resultItem.tags
I already tried everything i could find on forums, but it didn't work for me (It was for db's or for string datatypes)
Now, i really need your help. Thanks in advance.
For Each MEntry As EntryType In MainList
For Each Entry In MEntry.getTags
For Each item As String In Split(TextBox1.Text, " ")
If Entry.Contains(item) Then
If TestIfItemExistsInListBox2(item) = False Then
ListBox1.Items.Add(item & " - " & Entry.getId)
End If
End If
Next
Next
Next
Example Custom Array:
(24,{"snippet","vb"})
(32,{"console","cpp","helloworld"})
and so on...
I searched for ("Snippet vb test"):
snippet vb helloWorld - 2
snippet vb tcpchatEx - 16
cs something
test
So, i'll get everything that contains one of my search phrases.
I expected following:
snippet vb tcp test
snippet vb dll test
snippet vb test metroui
So, i want to get everything that contains all my search phrases.
My entire, code-likely class
Imports Newtonsoft.Json
Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Dim MainList As New List(Of EntryType)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
MainList.Clear()
Dim thr As New Threading.Thread(AddressOf thr1)
thr.SetApartmentState(Threading.ApartmentState.MTA)
thr.Start()
End Sub
Delegate Sub SetTextCallback([text] As String)
Private Sub SetTitle(ByVal [text] As String) ' source <> mine
If Me.TextBox1.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetTitle)
Me.Invoke(d, New Object() {[text]})
Else
Me.Text = [text]
End If
End Sub
Sub thr1()
Dim linez As Integer = 1
Dim linex As Integer = 1
For Each line As String In System.IO.File.ReadAllLines("index.db")
linez += 1
Next
For Each line As String In System.IO.File.ReadAllLines("index.db")
Try
Application.DoEvents()
Dim a As saLoginResponse = JsonConvert.DeserializeObject(Of saLoginResponse)(line) ' source <> mine
Application.DoEvents()
MainList.Add(New EntryType(a.id, Split(a.tags, " ")))
linex += 1
SetTitle("Search (loading, " & linex & " of " & linez & ")")
Catch ex As Exception
End Try
Next
SetTitle("Search")
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim searchTags() As String = TextBox1.Text.Split(" ")
Dim query = MainList.Where(Function(et) et.Tags.Any(Function(tag) searchTags.Contains(tag))).ToList
For Each et In query
ListBox1.Items.Add(et.Id)
Next
End Sub
Private Sub Button4_Click(sender As Object, e As EventArgs) ' test
MsgBox(Mid(ListBox1.SelectedItem.ToString, 1, 6)) ' test
End Sub 'test, removeonrelease
End Class
Public Class EntryType
Public Property Id As Integer
Public Property Tags() As String
Public Sub New(ByVal _id As Integer, ByVal _tags() As String)
Me.Id = Id
Me.Tags = Tags
End Sub
Public Function GetTags() As String
'to tell the Listbox what to display
Return Tags
End Function
Public Function GetId() As Integer
'to tell the Listbox what to display
Return Id
End Function
End Class
I also edited your EntryType class; I added a constructor, removed toString and added GetTags and GetID.
Example "DB" im working with ("db" as "index.db" in exec dir):
{"tags":"vb.net lol test qwikscopeZ","id":123456}
{"tags":"vb.net lol test","id":12345}
{"tags":"vb.net lol","id":1234}
{"tags":"vb.net","id":123}
{"tags":"cpp","id":1}
{"tags":"cpp graphical","id":2}
{"tags":"cpp graphical fractals","id":3}
{"tags":"cpp graphical fractals m4th","id":500123}
Error:
Debugger:Exception Intercepted: _Lambda$__1, Form2.vb line 44
An exception was intercepted and the call stack unwound to the point before the call from user code where the exception occurred. "Unwind the call stack on unhandled exceptions" is selected in the debugger options.
Time: 13.11.2014 03:46:10
Thread:<No Name>[5856]
Here is a Lambda query. The Where filters on a predicate, since Tags is an Array you can use the Any function to perform a search based on another Array-SearchTags. You can store each class object in the Listbox since it stores Objects, you just need to tell it what to display(see below).
Public Class EntryType
Public Property Id As Integer
Public Property Tags() As As String
Public Overrides Function ToString() As String
'to tell the Listbox what to display
Return String.Format("{0} - {1}", Me.Id, String.Join(Me.Tags, " "))
End Function
End Class
Dim searchTags = textbox1.Text.Split(" "c)
Dim query = mainlist.Where(Function(et) et.Tags.Any(Function(tag) searchTags.Contains(tag))).ToList
For Each et In query
Listbox1.Items.Add(et)
Next

The best way to extract data from a CSV file into a searchable datastructure?

I have a csv file with 48 columns of data.
I need to open this file, place it into a data structure and then search that data and present it in a DataRepeater.
So far I have successfully used CSVReader to extract the data and bind it to myDataRepeater. However I am now struggling to place the data in a table so that I can filter the results. I do not want to use SQL or any other database.
Does anyone have a suggestion on the best way to do this?
So far, this is working in returning all records:
Private Sub BindCsv()
' open the file "data.csv" which is a CSV file with headers"
Dim dirInfo As New DirectoryInfo(Server.MapPath("~/ftp/"))
Dim fileLocation As String = dirInfo.ToString & "data.txt"
Using csv As New CsvReader(New StreamReader(fileLocation), True)
myDataRepeater.DataSource = csv
myDataRepeater.DataBind()
End Using
End Sub
Protected Sub myDataRepeater_ItemDataBound(ByVal sender As Object, ByVal e As RepeaterItemEventArgs) Handles myDataRepeater.ItemDataBound
Dim dataItem As String() = DirectCast(e.Item.DataItem, String())
DirectCast(e.Item.FindControl("lblPropertyName"), ITextControl).Text = dataItem(2).ToString
DirectCast(e.Item.FindControl("lblPrice"), ITextControl).Text = dataItem(7).ToString
DirectCast(e.Item.FindControl("lblPricePrefix"), ITextControl).Text = dataItem(6)
DirectCast(e.Item.FindControl("lblPropertyID"), ITextControl).Text = dataItem(1)
DirectCast(e.Item.FindControl("lblTYPE"), ITextControl).Text = dataItem(18)
DirectCast(e.Item.FindControl("lblBedrooms"), ITextControl).Text = dataItem(8)
DirectCast(e.Item.FindControl("lblShortDescription"), ITextControl).Text = dataItem(37)
Dim dirInfo As New DirectoryInfo(Server.MapPath("~/ftp/images/"))
DirectCast(e.Item.FindControl("imgMain"), Image).ImageUrl = dirInfo.ToString & "pBRANCH_" & dataItem(1) & ".jpg"
DirectCast(e.Item.FindControl("linkMap"), HyperLink).NavigateUrl = "http://www.multimap.com/map/browse.cgi?client=public&db=pc&cidr_client=none&lang=&pc=" & dataItem(5) & "&advanced=&client=public&addr2=&quicksearch=" & dataItem(5) & "&addr3=&addr1="
End Sub
Code add to filter results:
Try
Dim csv As New CSVFile(fileLocation)
Dim ds As DataSet = csv.ToDataSet("MyTable")
If Not ds Is Nothing Then
Dim strExpr As String = "Bedrooms >= '3'"
Dim strSort As String = "PropertyID ASC"
'Use the Select method to find all rows matching the filter.
Dim myRows() As DataRow
'myRows = Dt.Select(strExpr, strSort)
myRows = csv.ToDataSet("MyTable").Tables("MyTable").Select(strExpr, strSort)
myDataRepeater.DataSource = myRows
myDataRepeater.DataBind()
End If
Catch ex As Exception
End Try
Which does return the two rows I am expecting but then when it binds to the datarepeater I get the following error:
DataBinding: 'System.Data.DataRow' does not contain a property with the name 'PropertyName'.
Corrected code, filter not being applied:
Public Sub PageLoad(ByVal Sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If Not Page.IsPostBack Then
ReadCsv()
lblSearch.Text = "Lettings Search"
End If
End Sub
Private Sub ReadCsv()
Dim dirInfo As New DirectoryInfo(Server.MapPath("~/ftp/"))
Dim fileLocation As String = dirInfo.ToString & "data.txt"
Try
Dim csv As New CSVFile(fileLocation)
Dim ds As DataSet = csv.ToDataSet("MyTable")
If Not ds Is Nothing Then
myDataRepeater.DataSource = ds
myDataRepeater.DataMember = ds.Tables.Item(0).TableName
myDataRepeater.DataBind()
End If
ds = Nothing
csv = Nothing
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles btnSubmit.Click
Dim rowCount As Integer
rowCount = QueryCsv()
pnlSearch.Visible = False
lblResults.Visible = True
lblSearch.Text = "Search Results"
lblResults.Text = "Your search returned " & rowCount.ToString & " results"
If rowCount > 0 Then
myDataRepeater.Visible = True
pnlResults.Visible = True
btnBack.Visible = True
End If
End Sub
Protected Function QueryCsv() As Integer
Dim dirInfo As New DirectoryInfo(Server.MapPath("~/ftp/"))
Dim fileLocation As String = dirInfo.ToString & "data.txt"
Dim numberofRows As Integer
Try
Dim csv As New CSVFile(fileLocation)
Dim ds As DataSet = csv.ToDataSet("MyTable")
If Not ds Is Nothing Then
Dim strExpr As String = "PropertyID = 'P1005'"
Dim strSort As String = "PropertyID DESC"
Try
ds.Tables.Item(0).DefaultView.RowFilter = strExpr
ds.Tables.Item(0).DefaultView.Sort = strSort
myDataRepeater.DataSource = ds.Tables.Item(0).DefaultView
Catch ex As Exception
End Try
End If
numberofRows = ds.Tables("MyTable").Rows.Count
Catch ex As Exception
End Try
Return numberofRows
End Function
Why not use the built-in TextFileParser to get the data into a DataTable? Something like Paul Clement's answer in this thread
One of the ways I've done this is by using a structure array and reflection.
First, set up your structure in a module: CSVFileFields.vb
Imports System.Reflection
Public Module CSVFileFields
#Region " CSV Fields "
Public Structure CSVFileItem
Dim NAME As String
Dim ADDR1 As String
Dim ADDR2 As String
Dim CITY As String
Dim ST As String
Dim ZIP As String
Dim PHONE As String
Public Function FieldNames() As String()
Dim rtn() As String = Nothing
Dim flds() As FieldInfo = Me.GetType.GetFields(BindingFlags.Instance Or BindingFlags.Public)
If Not flds Is Nothing Then
ReDim rtn(flds.Length - 1)
Dim idx As Integer = -1
For Each fld As FieldInfo In flds
idx += 1
rtn(idx) = fld.Name
Next
End If
Return rtn
End Function
Public Function ToStringArray() As String()
Dim rtn() As String = Nothing
Dim flds() As FieldInfo = Me.GetType.GetFields(BindingFlags.Instance Or BindingFlags.Public)
If Not flds Is Nothing Then
ReDim rtn(flds.Length - 1)
Dim idx As Integer = -1
For Each fld As FieldInfo In flds
idx += 1
rtn(idx) = fld.GetValue(Me)
Next
End If
Return rtn
End Function
Public Shadows Function ToString(ByVal Delimiter As String) As String
Dim rtn As String = ""
Dim flds() As FieldInfo = Me.GetType.GetFields(BindingFlags.Instance Or BindingFlags.Public)
If Not flds Is Nothing Then
For Each fld As FieldInfo In flds
rtn &= fld.GetValue(Me) & Delimiter
Next
rtn = rtn.Substring(0, rtn.Length - 1)
End If
Return rtn
End Function
End Structure
#End Region
End Module
Next we will make our own collection out of the structure we just made. This will make it easy to use .Add() .Remove() etc for our structure. We can also remove individual items with .RemoveAt(Index). File: CSVFileItemCollection.vb
#Region " CSVFileItem Collection "
Public Class CSVFileItemCollection
Inherits System.Collections.CollectionBase
Public Sub Add(ByVal NewCSVFileItem As CSVFileItem)
Me.List.Add(NewCSVFileItem)
End Sub
Public Sub Remove(ByVal RemoveCSVFileItem As CSVFileItem)
Me.List.Remove(RemoveCSVFileItem)
End Sub
Default Public Property Item(ByVal index As Integer) As CSVFileItem
Get
Return Me.List.Item(index)
End Get
Set(ByVal value As CSVFileItem)
Me.List.Item(index) = value
End Set
End Property
Public Shadows Sub Clear()
MyBase.Clear()
End Sub
Public Shadows Sub RemoveAt(ByVal index As Integer)
Remove(Item(index))
End Sub
End Class
#End Region
Next you need your class to handle the reflection import: CSVFile.vb
Imports System.Reflection
Imports System.IO
Imports Microsoft.VisualBasic.PowerPacks
Public Class CSVFile
#Region " Private Variables "
Private _CSVFile As CSVFileItem, _Delimiter As String, _Items As New CSVFileItemCollection
#End Region
#Region " Private Methods "
Private Sub FromString(ByVal Line As String, ByVal Delimiter As String)
Dim CSVFileElements() As String = Line.Split(Delimiter)
If Not CSVFileElements Is Nothing Then
Dim fldInfo() As FieldInfo = _CSVFile.GetType.GetFields(BindingFlags.Instance Or BindingFlags.Public)
If Not fldInfo Is Nothing Then
Dim itm As System.ValueType = CType(_CSVFile, System.ValueType)
For fldIdx As Integer = 0 To CSVFileElements.Length - 1
fldInfo(fldIdx).SetValue(itm, CSVFileElements(fldIdx).Replace(Chr(34), ""))
Next
_CSVFile = itm
Else
Dim itms As Integer = 0
If Not fldInfo Is Nothing Then
itms = fldInfo.Length
End If
Throw New Exception("Invalid line definition.")
End If
Else
Dim itms As Integer = 0
If Not CSVFileElements Is Nothing Then
itms = CSVFileElements.Length
End If
Throw New Exception("Invalid line definition.")
End If
End Sub
#End Region
#Region " Public Methods "
Public Sub New()
_CSVFile = New CSVFileItem
End Sub
Public Sub New(ByVal Line As String, ByVal Delimiter As String)
_CSVFile = New CSVFileItem
_Delimiter = Delimiter
FromString(Line, Delimiter)
End Sub
Public Sub New(ByVal Filename As String)
LoadFile(Filename)
End Sub
Public Sub LoadFile(ByVal Filename As String)
Dim inFile As StreamReader = File.OpenText(Filename)
Do While inFile.Peek > 0
FromString(inFile.ReadLine, ",")
_Items.Add(_CSVFile)
_CSVFile = Nothing
Loop
inFile.Close()
End Sub
#End Region
#Region " Public Functions "
Public Function ToDataSet(ByVal TableName As String) As DataSet
Dim dsCSV As DataSet = Nothing
If Not _Items Is Nothing AndAlso _Items.Count > 0 Then
Dim flds() As FieldInfo = _Items.Item(0).GetType.GetFields(BindingFlags.Instance Or BindingFlags.Public)
If Not flds Is Nothing Then
dsCSV = New DataSet
dsCSV.Tables.Add(TableName)
For Each fld As FieldInfo In flds
'Add Column Names
With dsCSV.Tables.Item(TableName)
.Columns.Add(fld.Name, fld.FieldType)
End With
Next
'Populate Table with Data
For Each itm As CSVFileItem In _Items
dsCSV.Tables.Item(TableName).Rows.Add(itm.ToStringArray)
Next
End If
End If
Return dsCSV
End Function
#End Region
#Region " Public Properties "
Public ReadOnly Property Item() As CSVFileItem
Get
Return _CSVFile
End Get
End Property
Public ReadOnly Property Items() As CSVFileItemCollection
Get
Return _Items
End Get
End Property
#End Region
End Class
Okay a little explanation. What this class is doing is first getting the line of delimited (",") text and splitting it into a string array. Then it iterates through every field you have in your structure CSVFileItem and based on the index populates that structure variable. It doesn't matter how many items you have. You could have 1 or 1,000 so long as the order in which your structure is declared is the same as the contents you are loading. For example, your input CSV should match CSVFileItem as "Name,Address1,Address2,City,State,Zip,Phone". That is done with this loop here from the above code:
Dim fldInfo() As FieldInfo = _CSVFile.GetType.GetFields(BindingFlags.Instance Or BindingFlags.Public)
If Not fldInfo Is Nothing Then
Dim itm As System.ValueType = CType(_CSVFile, System.ValueType)
For fldIdx As Integer = 0 To CSVFileElements.Length - 1
fldInfo(fldIdx).SetValue(itm, CSVFileElements(fldIdx).Replace(Chr(34), ""))
Next
_CSVFile = itm
Else
Dim itms As Integer = 0
If Not fldInfo Is Nothing Then
itms = fldInfo.Length
End If
Throw New Exception("Invalid line definition.")
End If
To make things easy, instead of having to load the file from our main class, we can simply pass it the file path and this class will do all of the work and return a collection of our structure. I know this seems like a lot of setup, but it's worth it and you can come back and change your original structure to anything and the rest of the code will still work flawlessly!
Now to get everything going. Now you get to see how easy this is to implement with only a few lines of code. File: frmMain.vb
Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Try
Dim csv As New CSVFile("C:\myfile.csv")
Dim ds As DataSet = csv.ToDataSet("MyTable")
If Not ds Is Nothing Then
'Add Labels
Dim lblSize As New Size(60, 22), lblY As Integer = 10, lblX As Integer = 10, lblSpacing As Integer = 10
For Each fldName As String In csv.Items.Item(0).FieldNames
Dim lbl As New Label
lbl.AutoSize = True
lbl.Size = lblSize
lbl.Location = New Point(lblX, lblY)
lbl.Name = "lbl" & fldName
lblX += lbl.Width + lblSpacing
lbl.DataBindings.Add(New Binding("Text", ds.Tables.Item(0), fldName, True))
drMain.ItemTemplate.Controls.Add(lbl)
Next
drMain.DataSource = ds
drMain.DataMember = ds.Tables.Item(0).TableName
End If
ds = Nothing
csv = Nothing
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
End Class
This really makes for some dynamic programming. You can wrap these in generic classes and call the functions for any structure. You then have some reusable code that will make your programs efficient and cut down on programming time!
Edit:
Added the ability to dump structure collection to a dataset and then dynamically fill a datarepeater.
Hope this helps. (I know this was a lot of information and seems like a lot of work, but I guarantee you that once you get this in place, it will really cut down on future projects coding time!)