VB 2008 - Filter txt file word for word - vb.net

Ok well I am working on a school project at the moment. Thats why I am using vb 2008. I have done pretty much everything on the project except one part. I have searched everywhere for an answer and still cant find one. So I decided to finally ask for some advice/help. Thanks
The problem:
So you fill in the details in the textboxes in the first image and hit save. The employee names are saved into one txt file. Each name on a new line.
The rest of the textboxes are saved into one txt file called report. Each textbox has a new line.
Once you hit main menu and go into the edit employee window. Which is the second image. The Employee list window will come up. It is just a list box. The list box then reads the employeenames txt file and displays the names. I want it so when you highlight one of the names from the employee list the corresponding info from report.txt will be read and placed into the correct text boxes. So you can edit and save the info once again.
what I need to work out:
I want to know the best way for me to filter and pull info line by line and place them in a textbox.
So when you highlight the name nicholas. his info will be taken from the txt file and the correct info be placed in the correct textbox. Also I am planning on using the sorted option in the list box to sort the names in employee list.
Im really new to this so cut me some slack if I didnt explain something correctly. Thanks

Here is how to:
first create your classes
Class employee
public name as String
....
end class
learn using List(t) how to use and how to sort using list on your own data ( you should implement iComparable interface or pass your Icompare when sorting and finding) or write those function by yourself
work with dummy data first to see if everything working like you want
then final saving and restoring your data.
You got many choices
using sql
using simple xml
and so on
I advise you to use xml first. reading xml and writing it. or u can directly serialize your data to xml file and deserialize it when restoring
.
Here is the what I found while searching. It uses Linq and xml serializer . And by the way that solution is merely same as yours.
http://www.codeproject.com/Articles/26652/Using-LINQ-to-Objects-in-Visual-Basic
And Here is my simple solution. I wrote it sorting and finding both way with Linq And without Linq .And you will need to store data . For that purpose check above link or this from msdn msdn serialize example
Imports System.Linq
Module Module1
Sub Main()
Dim employee_list As New List(Of Employee)
employee_list.Add(New Employee("Abdurrauf", 1, 1, "programmer"))
employee_list.Add(New Employee("John", 5, 2, "programmer"))
employee_list.Add(New Employee("Teylor", 10, 3, "programmer"))
employee_list.Add(New Employee("John", 9, 4, "student"))
employee_list.Add(New Employee("Jorj", 6, 5, "programmer"))
employee_list.Add(New Employee("Samir", 1, 6, "programmer"))
employee_list.Add(New Employee("Orxan", 3, 7, "programmer"))
'sort by annual and display
employee_list.Sort(Employee.GetSorter(SortType.AnualDesc))
Console.WriteLine("Sorted by annual leave {descending}:")
For Each x As Employee In employee_list
Console.WriteLine(" Name : {0} Annual : {1} ", x.Name, x.Annual_leave)
Next
'SORTING WITH LINQ
'using LINQ (this time you dont need to write sort class and you can avoid using it)
Dim employeesByNameDesc = From x In employee_list _
Order By x.Name Descending _
Select x
Console.WriteLine("Sorted with using Linq by Name Descending")
For Each x As Employee In employeesByNameDesc
Console.WriteLine(" Name : {0} Annual : {1} ", x.Name, x.Annual_leave)
Next
'find by name without lambda
Dim em As Employee = findemp(employee_list ,"Samir")
If em IsNot Nothing Then
Console.WriteLine("found : emp Name {0} desc {1} ", em.Name, em.Description)
End If
'find by name with lambda
Dim emp As Employee = employee_list.Find(Function(x) (x.Name = "John"))
If emp IsNot Nothing Then
Console.WriteLine("found : emp Name {0} desc {1} ", emp.Name, emp.Description)
End If
Console.Read()
End Sub
Function findemp(emlist As List(Of Employee), name As String) As Employee
For Each x In emlist
If (x.Name = name) = True Then
Return x
End If
Next
Return Nothing
End Function
<Serializable()> _
Class Employee
Implements IComparable(Of Employee)
Private _Name As String
Private _Annual_leave As Integer
Private _Sick_leave As Integer
Private _Description As String
Sub New(name As String, ann As Integer, sl As Integer, desc As String)
With Me
._Name = name
.Annual_leave = ann
.Sick_leave = sl
.Description = desc
End With
End Sub
Property Name As String
Get
Return _Name
End Get
Set(value As String)
_Name = value
End Set
End Property
Property Description As String
Get
Return _Description
End Get
Set(value As String)
_Description = value
End Set
End Property
Property Annual_leave As Integer
Get
Return _Annual_leave
End Get
Set(value As Integer)
_Annual_leave = value
End Set
End Property
Property Sick_leave As Integer
Get
Return _Sick_leave
End Get
Set(value As Integer)
_Sick_leave = value
End Set
End Property
'default compare
Public Overloads Function CompareTo(ByVal other As Employee) As Integer _
Implements IComparable(Of Employee).CompareTo
If other Is Nothing Then Return 1
Return Name.CompareTo(other.Name)
End Function
Public Shared Function GetSorter(sortType As SortType) As IComparer(Of Employee)
Return CType(New sortClass(sortType), IComparer(Of Employee))
End Function
End Class
''our comparer
Public Enum SortType
AnualAsc
AnualDesc
SickAsc
SickDesc
NameAsc
NameDesc
End Enum
Private Class sortClass
Implements IComparer(Of Employee)
Dim _type As SortType
Private _sortType As SortType
Sub New(sortType As SortType)
_sortType = sortType
End Sub
Private Function compareint(xx As Integer, yy As Integer) As Integer
If (xx < yy) = True Then
Return 1
ElseIf (xx > yy) = True Then
Return -1
Else
Return 0
End If
End Function
Public Overloads Function Compare(x As Employee, y As Employee) As Integer _
Implements IComparer(Of Employee).Compare
Dim res As Integer = 0
Select Case _type
Case SortType.NameAsc
res = String.Compare(x.Name, y.Name)
Case SortType.NameDesc
res = String.Compare(y.Name, x.Name)
Case SortType.AnualAsc
res = compareint(x.Annual_leave, y.Annual_leave)
Case SortType.AnualDesc
res = compareint(y.Annual_leave, x.Annual_leave)
Case SortType.SickAsc
res = compareint(x.Sick_leave, y.Sick_leave)
Case SortType.SickDesc
res = compareint(y.Sick_leave, x.Sick_leave)
Case Else
res = String.Compare(x.Name, y.Name)
End Select
Return res
End Function
End Class
End Module

If you make it so the file is saved as the Employees name, then you can use this method
Dim DirectoryLocation As String = "YOUR DIRECTORY HERE"
For Each foundFile As String In My.Computer.FileSystem.GetFiles(
DirectoryLocation)
ComboBox1.Items.Add(foundFile)
Next
That is the simplest way I can see to do this. It lists all the files in the folder. But shows the directory so if you don't want that then do this:
Dim DirectoryLocation As String = "YOUR DIRECTORY HERE"
'Example: "C:\temp\" It must END in a \
For Each foundFile As String In My.Computer.FileSystem.GetFiles(
DirectoryLocation)
foundFile = foundFile.Replace(DirectoryLocation, Nothing)
foundFile = foundFile.Replace(".txt", Nothing)
ComboBox1.Items.Add(foundFile)
Next
That then repalces all the directory location from the files found and the .txt - I hope it helps if you need any more help just reply or PM me or something :)
-nfell2009

Related

Adding member to list overides previous members

I need to read from an Excel file a list of dogs with their birth date, and store them in a list. The read works well, and every time I add a new dog to the list, the list count grows. So far so good.
The problem is that when I add the 2nd record, the first record is replaced by the first record content, so I have two identical records. And so on with every new record. In the end, I have many same records - all with the value of the last dog.
The dog class is:
Public Class DogClass
Public Name As String
Public Dob As Date
Public Age As Integer
Public Sex As String
Public Sub setDogName(ByVal _name As String)
Name = _name
End Sub
Public Sub setDogDOB(ByVal _dob As Date)
Dob = _dob
End Sub
Public Sub setDogAge(ByVal _age As String)
Age = _age
End Sub
Public Sub setDogSex(ByVal _sex As String)
Sex = _sex
End Sub
End Class
The class of the list is:
Public Class DogsListClass
Public dogsList As New List(Of DogClass)
Public Function DodgsCnt() As Integer
DodgsCnt = dogsList.Count()
End Function
Public Function DogExsists(_dogName As String) As Boolean
Dim res As Boolean = False
For Each item As DogClass In dogsList
If item.Name = _dogName Then
res = True
End If
Next
Return res
End Function
Public Sub AddDog(_dog As DogClass)
dogsList.Add(_dog)
End Sub
End Class
The calling:
Dim tdog As New DogClass
Dim DogsList As New DogsListClass
Do
tdog.setDogName(MyExcel.Cells(row_cnt, col_cnt).text)
tdog.setDogDOB(MyExcel.Cells(row_cnt, col_cnt + 1).value)
DogsList.AddDog(tdog)
Loop
Any idea why the records are being overridden?
DogsList variable must be declared outside the Do...Loop, otherwise you are creating a "New" DogsList at each iteration and, based on this code, you should end up having one single item in the collection, not many.
Also, declaring DogsList in the loop, prevents you from using it outside in the rest of your code.

Delete duplicates from list

I have the following class :
Public Class titlesclass
Public Property Link As String
Public Property Title As String
Public Function Clear()
Link.Distinct().ToArray()
Title.Distinct().ToArray()
End Function
End Class
And the following code :
For Each title As Match In (New Regex(pattern).Matches(content)) 'Since you are only pulling a few strings, I thought a regex would be better.
Dim letitre As New titlesclass
letitre.Link = title.Groups("Data").Value
letitre.Title = title.Groups("Dataa").Value
lestitres.Add(letitre)
'tempTitles2.Add(title.Groups("Dataa").Value)
Next
I tried to delete the duplicated strings using the simple way
Dim titles2 = lestitres.Distinct().ToArray()
And calling the class function :
lestitres.Clear()
But the both propositions didn't work , i know that i'm missing something very simple but still can't find what it is
Easier to use a class that already implements IComparable:
Dim query = From title In Regex.Matches(content, pattern).Cast(Of Match)
Select Tuple.Create(title.Groups("Data").Value, title.Groups("Dataa").Value)
For Each letitre In query.Distinct
Debug.Print(letitre.Item1 & ", " & letitre.Item2)
Next
or Anonymous Types:
Dim query = From title In Regex.Matches(content, pattern).Cast(Of Match)
Select New With {Key .Link = title.Groups("Data").Value,
Key .Title = title.Groups("Dataa").Value}
For Each letitre In query.Distinct
Debug.Print(letitre.Link & ", " & letitre.Title)
Next
Ok, Since I notice you are using a ClassHere is one option you can do in order to not add duplicate items to your List within a class.I'm using a console Application to write this example, it shouldn't be too hard to understand and convert to a Windows Form Application if need be.
Module Module1
Sub Main()
Dim titlesClass = New Titles_Class()
titlesClass.addNewTitle("myTitle") ''adds successfully
titlesClass.addNewTitle("myTitle") '' doesn't add
End Sub
Public Class Titles_Class
Private Property Title() As String
Private Property TitleArray() As List(Of String)
Public Sub New()
TitleArray = New List(Of String)()
End Sub
Public Sub addNewTitle(title As String)
Dim added = False
If Not taken(title) Then
Me.TitleArray.Add(title)
added = True
End If
Console.WriteLine(String.Format("{0}", If(added, $"{title} has been added", $"{title} already exists")))
End Sub
Private Function taken(item As String) As Boolean
Dim foundItem As Boolean = False
If Not String.IsNullOrEmpty(item) Then
foundItem = Me.TitleArray.Any(Function(c) -1 < c.IndexOf(item))
End If
Return foundItem
End Function
End Class
End Module
Another option would be to use a HashSet, It will never add a duplicate item, so even if you add an item with the same value, it wont add it and wont throw an error
Sub Main()
Dim titlesClass = New HashSet(Of String)
titlesClass.Add("myTitle") ''adds successfully
titlesClass.Add("myTitle") '' doesn't add
For Each title As String In titlesClass
Console.WriteLine(title)
Next
End Sub
With all of that aside, have you thought about using a Dictionary so that you could have the title as the key and the link as the value, that would be another way you could not have a list (dictionary) contain duplicate items

Binary Searching in a List and Referring to a Specific Column of the List

I have some two column data that I read from a file and put into a list then sort alphabetically.
//The file
Hummus,0.75
Chili,0.50
Tabouli,1.25
Tzatziki,0.50
//Declaring the variables and public properties
Dim extraList As List(Of extra)
Public Class extra
Implements IComparable(Of extra)
Public Property Name As String
Public Property Price As Decimal
'Public Property extraList As List(Of extra)
Public Function CompareTo(other As extra) As Integer Implements IComparable(Of extra).CompareTo
Return Me.Name.CompareTo(other.Name)
End Function
End Class
//Puts the data into a list and sorts it
Sub Get_Extras_List()
'Reads the extras file and puts the information into a list, splitting the name of the extra and the price into separate columns
Dim allExtras = From line In System.IO.File.ReadLines("C:\Users\ExtrasList.txt")
Let Columns = line.Split(","c)
Where Columns.Length = 2
Let Price = Decimal.Parse(Columns(1).Trim())
Let Name = Columns(0).Trim()
Select New extra With {.Name = Name, .Price = Price}
extraList = allExtras.ToList()
'Sort the list alphabetically
extraList.Sort()
End Sub
Now I need to code a method that allows the user to type in an extra and search for it using a binary search to see if it exists. So far I have tried this but it just doesn't work and even if it did how do I get it to return a true or false value? (If it exists or not?)
Sub Search_Extras_List()
Dim strSearchExtra As String = Console.ReadLine()
Console.WriteLine(vbLf & "BinarySearch for '{0}':", strSearchExtra)
Dim index As Integer =
List(Of extra).BinarySearch(extraList.Name, strSearchExtra)
End Sub
Finally I have to get the user to choose one of the extras and then add the price of it to the total price. How do I refer to the price? extraList.Price? extra.Price? etc.
If you want to do a binary search like that, you will need to write a comparer.
Referring to List(Of T).BinarySearch Method (T, IComparer(Of T)), it could be
Public Class ExtraComparer
Implements IComparer(Of extra)
Public Function Compare(ByVal x As extra, ByVal y As extra) As Integer Implements IComparer(Of extra).Compare
If x Is Nothing Then
If y Is Nothing Then
' If x is Nothing and y is Nothing, they're equal.
Return 0
Else
' If x is Nothing and y is not Nothing, y is greater.
Return -1
End If
Else
' If x is not Nothing...
If y Is Nothing Then
' ...and y is Nothing, x is greater.
Return 1
Else
' ...and y is not Nothing, compare the names of the two extras.
'
Return x.Name.CompareTo(y.Name)
End If
End If
End Function
End Class
Which you can test with
' Get some item from the data so we know it is present...
Dim a = extraList(2).Name
Dim lookFor As New extra With {.Name = a}
Dim idx = extraList.BinarySearch(lookFor, New ExtraComparer)
Console.WriteLine($"Index of {a} is {idx}.")
(although you would probably want to do a case-insensitive string comparison).
If the index returned is negative then the item was not found. (See the documentation linked to above for more details.)
However, you might find it easier to use LINQ:
Dim a = extraList(2).Name
Dim chosenExtra = extraList.FirstOrDefault(Function(x) x.Name.Equals(a, StringComparison.CurrentCultureIgnoreCase))
If chosenExtra IsNot Nothing Then
Console.WriteLine($"User chose {chosenExtra.Name} at a price of {chosenExtra.Price}")
Else
Console.WriteLine($"User's choice of ""{a}"" was not found.")
End If
I used a case-insensitive comparison in there.
Or Just present the user with a dropdown of the available extras so that they don't have to type it.

How to query an arraylist using Linq that stores dictionaries

The following code reads query results from oracle data reader and stores each record in a dictionary and appends the dictionaries to an array list :
Dim dr As OracleDataReader = cmd.ExecuteReader()
'loop oracle data records and store them to dictionaries
'append dictionaries to an array list
Dim arr As New ArrayList
While dr.Read
Dim dict As New Dictionary(Of String, Object)
For count As Integer = 0 To (dr.FieldCount - 1)
dict.Add(dr.GetName(count), dr(count))
Next
arr.Add(dict)
End While
How do I write a LINQ query that can be used to retrieve values from the dictionaries stored in the array list? Please help. I've been searching and have not got any good answers
First of all, don't use ArrayList, ever. It is there for backwards compatibility but has no usage. I can make answer short - there is no use of LINQ with ArrayList. Use generic List(Of T) and LINQ to search values in it. No need for Dictionary either. This is the old style. We used Dictionary because it has key
I see, you trying to create your table structure but no need for this. First of all, there is System.Data.DataTable, which can be queried on client.
Or use this technique
Public Class User
Public Property Id As Integer
Public Property Name As String
Public Property Email As String
Public Property Country As String
End Class
Private Function LoadUsers() As List(Of User)
Dim uList As New List(Of User)()
' Some Code goes here
While dr.Read()
Dim u As New User()
u.Id = dr("Id")
u.Name = dr("Name")
u.Email = dr("Email")
u.Country = dr("Country")
uList.Add(u)
End While
. . . . . . .
Return uList
End While
' somewhere in class set member variable
_users = LoadUsers()
' And then you can search for info using LINQ
Public Function FindByCountry(ByVal country As String) As List(Of User)
Return _users.Where(Function(u) u.Country.Equals(country, StringComparison.OrdinalIgnoreCase))
End
The downside of this approach - you need Find function for each field. But what if you can pass a function itself. See- you have Name, email, Country - all strings. Here what you can do
Class Client
Sub SearchStrings(ByVal searchOption String, Byval searchValue As String)
Dim f As Func(Of User, boolean)
If searchOption = "Name" Then
f = Function(u as User)(u.Name.Equals(searchValue , Stringcomparison.OrdinalIgnoreCase))
ElseIf searchOption = "Country" Then
f = Function(u as User)(u.Country.Equals(searchValue , Stringcomparison.OrdinalIgnoreCase))
ElseIf searchOption = "Email" Then
f = Function(u as User)(u.Email.Equals(searchValue , Stringcomparison.OrdinalIgnoreCase))
Else
. . . .
End If
dataGrd.DataSource = myRepository.FindByString(f)
End Sub
End Class
' In your repository class
public sub FindByString(ByVal f as Func(Of String, Boolean)) As List(Of User)
_users.Where(f).ToList()
End sub
' use this to search single user
public sub FindByInteger(ByVal f as Func(Of Integer, Boolean)) As User
_users.SingleOrDefault(f)
End sub
The bottom line - drop what you do and use modern and efficient techniques. And above are just couple of them

How to convert a string of key/value pairs to HashTable or Dictionary or?

In VB.NET, how can I convert the following string into some kind of key/value type such as a Hashtable, Dictionary, etc?
"Name=Fred;Birthday=19-June-1906;ID=12345"
I want to extract Birthday or ID without having to split the string into an array.
EDIT: I'd prefer not to split the string into an array in case the format of the string changes later. I don't have control over the string. What if someone switches the order around or adds another element?
I’m currently unable to test this, lacking a VB compiler, but the following solution should also work, and it has the advantage of not requiring an explicit loop. It uses the Linq method ToDictionary and two nested Split operations:
Dim s = "Name=Fred;Birthday=19-June-1906;ID=12345"
Dim d = s.Split(";"c).Select(Function (kvp) kvp.Split("="c)) _
.ToDictionary( _
Function (kvp) kvp(0), _
Function (kvp) kvp(1))
First, we split on the outer delimiter (i.e. the semi-colon). From the resulting array, we select by splitting again, this time on =. The resulting array of arrays is converted to a dictionary by specifying that the first item is to become the key and the second is to become the value (the identifier kvp stands for “key-value pair”).
Since I can’t check the exact VB syntax and the above may contain subtle errors, here is the equivalent C# code (tested for correctness):
var s = "Name=Fred;Birthday=19-June-1906;ID=12345";
var d = s.Split(';').Select(kvp => kvp.Split('='))
.ToDictionary(kvp => kvp[0], kvp => kvp[1]);
Not sure why you don't want to split it. If you're sure there won't be any extra = or ; then you could just do:
Dim s As String = "Name=Fred;Birthday=19-June-1906;ID=12345"
Dim d As New Dictionary(Of String, String)
For Each temp As String In s.Split(";"c)
Dim index As Int32 = temp.IndexOf("="c)
d.Add(temp.Substring(0, index), temp.Substring(index + 1))
Next
Which might not be beautiful, but is very easy to understand.
input.Split(";"c) returns an array of key/value:
{ "Name=Fred", "Birthday=19-June-1906" , "ID=12345" }
so pair.Split("="c) returns { "Name", "Fred" } etc
If you want an alternative to doing a String.Split; there is always Regular Expressions as an alternative:
Dim map As Dictionary(Of String, String) = New Dictionary(Of String, String)
Dim match As Match = Regex.Match("Name=Fred;Birthday=19-June-1906;ID=12345", "(?<Name>[^=]*)=(?<Value>[^;]*);?")
While (match.Success)
map.Add(match.Groups("Name").Value, match.Groups("Value").Value)
match = match.NextMatch()
End While
The regular expression itself could be beefed up to better handle whitespace between key/value's and pair's but you hopefully get the idea. This should only pass through the string once to build up a string dictionary of keys and values.
Dim persSeparator as string=";"
Dim keyValSeparator as string="=";
Dim allPersons As New Dictionary(Of String, Person)
Dim str As String = "Name=Fred;Birthday=19-June-1906;ID=12345"
Dim parts As New List(Of String)(str.Split(persSeparator.ToCharArray)) 'why dont want you to split this string??
Dim person As New Person
For Each part As String In parts
Dim keyValue() As String = part.Split(keyValSeparator.toCharArray())
Select Case keyValue(0).ToUpper
Case "ID"
person.ID = keyValue(1)
Case "NAME"
person.Name = keyValue(1)
Case "BIRTHDAY"
person.BirthDay= keyValue(1)
End Select
Next
If Not allPersons.ContainsKey(person.ID) Then
allPersons.Add(person.ID, person)
End If
Public Class Person
Private _name As String
Private _birthday As String
Private _id As String = String.Empty
Public Sub New()
End Sub
Public Sub New(ByVal id As String)
Me._id = id
End Sub
Public Sub New(ByVal id As String, ByVal name As String)
Me._id = id
Me._name = name
End Sub
Public Sub New(ByVal id As String, ByVal name As String, ByVal birthday As String)
Me._id = id
Me._name = name
Me._birthday = birthday
End Sub
Public Property ID() As String
Get
Return Me._id
End Get
Set(ByVal value As String)
Me._id = value
End Set
End Property
Public Property Name() As String
Get
Return Me._name
End Get
Set(ByVal value As String)
Me._name = value
End Set
End Property
Public Property BirthDay() As String
Get
Return Me._birthday
End Get
Set(ByVal value As String)
Me._birthday = value
End Set
End Property
Public Overrides Function Equals(ByVal obj As Object) As Boolean
If TypeOf obj Is Person AndAlso Not obj Is Nothing Then
Return String.Compare(Me._id, DirectCast(obj, Person).ID) = 0
Else : Return False
End If
End Function
End Class
If you were just wanting to extract the birthday and ID from the string and place as a value pair in some sort of dictionary, for simplicity I would use regular expressions and then a generic dictionary (of string, valuepair structure). Something like this:
Imports System.Text.RegularExpressions
Imports System.Collections.Generic
Sub Main()
Dim Person As New Dictionary(Of String, ValuePair)
Dim s As String = "Name=Fred;Birthday=19-June-1906;ID=12"
Dim r As Regex = New Regex("Name=(.*);Birthday=(.*);ID=(.*$)")
Dim m As Match = r.Match(s)
Person.Add(CStr(m.Groups(1).Value), _
New ValuePair(CDate(m.Groups(2).Value), CInt(m.Groups(3).Value)))
Console.WriteLine(Person("Fred").Birthday.ToString)
Console.WriteLine(Person("Fred").ID.ToString)
Console.Read()
End Sub
Friend Structure ValuePair
Private _birthday As Date
Private _ID As Int32
Public ReadOnly Property ID() As Int32
Get
Return _ID
End Get
End Property
Public ReadOnly Property Birthday() As Date
Get
Return _birthday
End Get
End Property
Sub New(ByVal Birthday As Date, ByVal ID As Int32)
_birthday = Birthday
_ID = ID
End Sub
End Structure