I have an error where I am trying to load a player's name and score to the first open space of the array, but it is creating duplicates of that name over and over in the array. Thanks in advance
Structure Player
Dim Name As String
Dim Score As Integer
End Structure
Public HighScores(100) As Player
For i = 0 To 99
If HighScores(i).Name = "" And HighScores(i).Score = 0 Then
HighScores(i).Name = PlayerName
HighScores(i).Score = CurrentScore
Else
i += 1
End If
Next
Your current code will set the supplied values in every empty index it finds. You need to stop setting the values (exit the loop) once you have found your empty index and set it's value.
For i = 0 To 99
If HighScores(i).Name.Length = 0 AndAlso HighScores(i).Score = 0 Then 'Determines if the index is empty
HighScores(i).Name = PlayerName
HighScores(i).Score = CurrentScore 'Sets the values
Exit For 'Exits the loop
End If
Next
The above code will only run through the loop once if the first index matches your requirements, twice if the first index does not but the second does and so forth.
To avoid looping through the array looking for an empty slot use a List(Of T) as suggested by David Wilson in comments. The T stands for Type and Player is a Type. This restricts your list to only objects of type Player. I included a bit to sort your list using LINQ to Objects. There are in line comments. Although I think a list would be a better approach, The White Wolf's answer with the Exit For should solve your problem.
Structure Player
Public Score As Integer
Public Name As String
'Added a constructor to the structure to make it easy to add new Player
Public Sub New(myScore As Integer, myName As String)
Score = myScore
Name = myName
End Sub
End Structure
Private lstScores As New List(Of Player)
Private Sub BuildList()
lstScores.Add(New Player(500, "Mathew"))
lstScores.Add(New Player(200, "Mark"))
lstScores.Add(New Player(300, "Luke"))
lstScores.Add(New Player(700, "John"))
'Sort and display list
SortList()
End Sub
Private Sub AddScore(strName As String, intScore As Integer)
lstScores.Add(New Player(intScore, strName))
End Sub
Private Sub SortList()
'Note: the original lstScores is not changed
Dim orderedList = From scorer In lstScores Order By scorer.Score Descending Select $"{scorer.Score} - {scorer.Name}"
'orderedList is an IEnumerable(Of String) because the Select part of the LINQ query is a string.
'Using .ToList provides the DataSource of the ListBox with the formatted strings
'Display the sorted list in a list box
ListBox1.DataSource = orderedList.ToList
End Sub
Related
I am trying to stay ahead of my Year 12 Software class. Starting to work with records and arrays. I have answered the question, but the solution feels very clunky. I am hoping someone has suggestions/links for completing this task in a more efficient way.
The task: read in lines from a text file and into a structure, and then loop through that, populating four list boxes if an animal hasn't been vaccinated.
Here's the code:
Imports System.IO
Public Class Form1
'Set up the variables - customer record, total pets not vaccinated, total records in the file, and a streamreader for the file.
Structure PetsRecord
Dim custName As String
Dim address As String
Dim petType As String
Dim vacced As String
End Structure
Dim totNotVac As Integer
Dim totalRecCount As Integer
Dim PetFile As IO.StreamReader
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
'set an array of records to store each record as it comes in. Limitation: you need to know how many records in the file. Set the array at 15 to allow for adding more in later.
Dim PetArray(15) As PetsRecord
'variables that let me read in a line and split it into sections.
Dim lineoftext As String
Dim i As Integer
Dim arytextfile() As String
'tell them what text file to read
PetFile = New IO.StreamReader("patients.txt")
totNotVac = 0
Try
totalRecCount = 0
' read each line in and split the lines into fields for the records. Then assign the fields from the array. Finally, reset the array and loop.
Do Until PetFile.Peek = -1
'read in a line of text
lineoftext = PetFile.ReadLine()
'split that line into bits separated by commas. these will go into the array.
arytextfile = lineoftext.Split(",")
'dunno whether this is the best way to do it, but stick the array bits into the record, and then clear the array to start again.
PetArray(totalRecCount).custName = arytextfile(0)
PetArray(totalRecCount).address = arytextfile(1)
PetArray(totalRecCount).petType = arytextfile(2)
PetArray(totalRecCount).vacced = arytextfile(3)
totalRecCount += 1
Array.Clear(arytextfile, 0, arytextfile.Length)
Loop
For i = 0 To PetArray.GetUpperBound(0)
If PetArray(i).vacced = "No" Then
lstVaccinated.Items.Add(PetArray(i).vacced)
lstCustomer.Items.Add(PetArray(i).custName)
lstAddress.Items.Add(PetArray(i).address)
lstPetType.Items.Add(PetArray(i).petType)
totNotVac += 1
lblVacTotal.Text = "The total number of unvaccinated animals is " & CStr(totNotVac)
End If
Next
Catch ex As Exception
MsgBox("Something went wrong with the file")
End Try
PetFile.Close()
End Sub
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Close()
End Sub
End Class
And one line from the patient.txt file:
Richard Gere,16 Sunset Blvd,Gerbil,No
I hope this isn't out of place.
Regards,
Damian
If you want to use Streams be aware that they need to be disposed.
File.ReadAllLines returns an array of lines. Since the array is initialized where it is declared we don't need to specify a size.
If you use List(Of T) you do not have to know in advance the number of elements in the list. Avoids the limitation of array.
Using a For Each avoids having to use the size. The small c following "," tells the compiler that this is a Char which is what .Split is expecting. If you had Option Strict On, which you always should, you would have seen an error. You add items to the list by creating a New PetsRecord. The parametrized Sub New receives the values and sets the properties.
Don't change the display in the label on each iteration. Use an interpolated string (preceded by a $) which allows embedded variables surrounded by braces { }. It is not necessary to change the number to a string as it is implied by the interpolator. (Available in VS2015 and later)
Public Structure PetsRecord
Public Property custName As String
Public Property address As String
Public Property petType As String
Public Property vacced As String
Public Sub New(name As String, add As String, pType As String, vac As String)
custName = name
address = add
petType = pType
vacced = vac
End Sub
End Structure
Private Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
Dim lines = File.ReadAllLines("patients.txt")
Dim lstPet As New List(Of PetsRecord)
For Each line In lines
Dim splits = line.Split(","c)
lstPet.Add(New PetsRecord(splits(0), splits(1), splits(2), splits(3)))
Next
Dim totNotVac As Integer
For Each pet In lstPet
If pet.vacced = "No" Then
lstVaccinated.Items.Add(pet.vacced)
lstCustomer.Items.Add(pet.custName)
lstAddress.Items.Add(pet.address)
lstPetType.Items.Add(pet.petType)
totNotVac += 1
End If
Next
lblVacTotal.Text = $"The total number of unvaccinated animals is {totNotVac}"
End Sub
If you don't need the 'PetsRecord' array to store data, take a look at the following code:
Dim totNotVac As Integer
Private Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
File.ReadAllLines("your text file path").ToList().ForEach(Sub(x)
lstVaccinated.Items.Add(x.Split(","c)(0))
lstCustomer.Items.Add(x.Split(","c)(1))
lstAddress.Items.Add(x.Split(","c)(2))
lstPetType.Items.Add(x.Split(","c)(3))
totNotVac += 1
End Sub)
lblVacTotal.Text = "The total number of unvaccinated animals is " & CStr(totNotVac)
End Sub
I have to make a application that organizes a list of runners and their teams. In the following text file, I have to remove the top half of the text file (the top half being the listed teams) and display only the bottom half (the runners)in a listbox item.
The Text file:
# School [School Code|School Name|Coach F-Name|Coach L-Name|AD F-Name|AD L Name]
WSHS|Worcester South High School|Glenn|Clauss|Bret|Zane
WDHS|Worcester Dorehty High School|Ellsworth|Quackenbush|Bert|Coco
WBCHS|Worcester Burncoat High School|Gail|Cain|Kevin|Kane
QRHS|Quabbin Regional High School|Bob|Desilets|Seth|Desilets
GHS|Gardner High School|Jack|Smith|George|Fanning
NBHS|North Brookfield High School|Hughe|Fitch|Richard|Carey
WHS|Winchendon High School|Bill|Nice|Sam|Adams
AUBHS|Auburn High School|Katie|Right|Alice|Wonderland
OXHS|Oxford High School|Mary|Cousin|Frank|Daughter
# Roster [Bib #|School Code|Runner's F-Name|Runner's L-Name]
101|WSHS|Sanora|Hibshman
102|WSHS|Bridgette|Moffitt
103|WSHS|Karine|Chunn
104|WSHS|Shanita|Wind
105|WSHS|Fernanda|Parsell
106|WSHS|Albertha|Baringer
107|WSHS|Carlee|Sowards
108|WDHS|Maisha|Kleis
109|WDHS|Lezlie|Berson
110|WDHS|Deane|Rocheleau
111|WDHS|Hang|Hodapp
112|WDHS|Zola|Dorrough
113|WDHS|Shalon|Mcmonigle
I have some code that reads each row from the text file as an array and uses boolean variables to determine where to end the text file. This worked with displaying only the teams, which I've managed to do. But I now need to do the opposite and display only the players, and I'm a bit stumped.
My Code:
Private Sub btnLoadTeams_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoadTeam.Click
' This routine loads the lstTeam box from an ASCII .txt file
' # School [School Code | Name | Coach F-Name| Coach L-Name | AD F-Name | AD L-Name]
Dim strRow As String
Dim bolFoundCode As Boolean = False
Dim bolEndCode As Boolean = False
Dim bolFoundDup As Boolean = False
Dim intPosition As Integer
Dim intPosition2 As Integer
Dim strTeamCodeIn As String
Dim textIn As New StreamReader( _
New FileStream(txtFilePath.Text, FileMode.OpenOrCreate, FileAccess.Read))
' Clear Team listbox
lstTeam.Items.Clear()
btnDeleteRunner.Enabled = True
Do While textIn.Peek <> -1 And Not bolEndCode
Me.Refresh()
strRow = textIn.ReadLine.Trim
If Not bolFoundCode Then
If "# SCHOOL " = UCase(Mid(strRow, 1, 9)) Then
bolFoundCode = True
End If
Else
If Mid(strRow, 1, 2) <> "# " Then
For Each item As String In lstTeam.Items
intPosition = InStr(1, strRow, "|")
strTeamCodeIn = Mid(strRow, 1, intPosition - 1)
intPosition2 = InStr(1, item, strTeamCodeIn)
If intPosition2 > 0 Then
bolFoundDup = True
MsgBox("Found Duplicate School Code: " & strTeamCodeIn)
End If
Else
bolEndCode = True
Next
If Not bolFoundDup Then
lstTeam.Items.Add(strRow)
Else
lstTeam.Items.Add("DUPLICATE School Code: " & strRow)
lstTeam.Items.Add("Please correct input file and reload teams")
bolEndCode = True
End If
End If
End If
Loop
End Sub
Ive put bolEndCode = True in between the part that reads the mid section of the text file, but all Ive managed to display is the following in the listbox:
# Roster [Bib #|School Code|Runner's F-Name|Runner's L-Name]
Any help or hints on how I would display just the runners to my "lstPlayers" listbox would be greatly appreciated. I'm a beginner programmer and We've only just started learning about reading and writing arrays in my .NET class.
First I made 2 classes, one Runner and one School. These have the properties available in the text file. As part of the class I added a function that overrides .ToString. This is for he list boxes that call .ToString for display.
Next I made a function that reads all the data in the file. This is very simple with the File.ReadLines method.
Then I created 2 variables List(Of T) T stands for Type. Ours Types are Runner and School. I used List(Of T) instead of arrays because I don't have to worry about what the size of the list is. No ReDim Preserve, just keep adding items. The FillList method adds the data to the lists. First I had to find where the schools ended and the runners started. I used the Array.FindIndex method which is a bit different because the second parameter is a predicate. Check it out a bit. Now we know the indexes of the lines we want to use for each list and use a For...Next loop. In each loop an instance of the class is created and the properties set. Finally the new object is added to the the list.
Finally we fill the list boxes with a simple .AddRange and the lists.ToArray. Note that we are adding the entire object, properties and all. The neat thing is we can access the properties from the listbox items. Check out the SelectedIndexChanged event. You can do the same thing with the Runner list box.
Sorry, I couldn't just work with your code. I have all but forgotten the old vb6 methods. InStr, Mid etc. It is better when you can to use .net methods. It makes your code more portable when the boss says "Rewrite the whole application in C#"
Public Class Runner
Public Property BibNum As Integer
Public Property SchoolCode As String
Public Property FirstName As String
Public Property LastName As String
Public Overrides Function ToString() As String
'The listbox will call .ToString when we add a Runner object to determin what to display
Return $"{FirstName} {LastName}" 'or $"{LastName}, {FirstName}"
End Function
End Class
Public Class School
Public Property Code As String
Public Property Name As String
Public Property CoachFName As String
Public Property CoachLName As String
Public Property ADFName As String
Public Property ADLName As String
'The listbox will call .ToString when we add a School object to determin what to display
Public Overrides Function ToString() As String
Return Name
End Function
End Class
Private Runners As New List(Of Runner)
Private Schools As New List(Of School)
Private Function ReadData(path As String) As String()
Dim lines = File.ReadLines(path).ToArray
Return lines
End Function
Private Sub FillLists(data As String())
Dim location = Array.FindIndex(data, AddressOf FindRosterLine)
'The first line is the title so we don't start at zero
For index = 1 To location - 1
Dim SplitData = data(index).Split("|"c)
Dim Schl As New School
Schl.Code = SplitData(0)
Schl.Name = SplitData(1)
Schl.CoachFName = SplitData(2)
Schl.CoachLName = SplitData(3)
Schl.ADFName = SplitData(4)
Schl.ADLName = SplitData(5)
Schools.Add(Schl)
Next
For index = location + 1 To data.GetUpperBound(0)
Dim SplitData = data(index).Split("|"c)
Dim Run As New Runner
Run.BibNum = CInt(SplitData(0))
Run.SchoolCode = SplitData(1)
Run.FirstName = SplitData(2)
Run.LastName = SplitData(3)
Runners.Add(Run)
Next
End Sub
Private Function FindRosterLine(s As String) As Boolean
If s.Trim.StartsWith("# Roster") Then
Return True
Else
Return False
End If
End Function
Private Sub FillListBoxes()
Dim arrRunners As Runner() = Runners.ToArray
Dim arrSchools As School() = Schools.ToArray
ListBox1.Items.AddRange(arrSchools)
ListBox2.Items.AddRange(arrRunners)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim arrRunner = ReadData("Runners.txt")
FillLists(arrRunner)
FillListBoxes()
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
Dim Schl = DirectCast(ListBox1.SelectedItem, School)
TextBox1.Text = Schl.CoachLName
TextBox2.Text = Schl.Code
End Sub
I have multiple text files with similar data, for instance file1 would have the following entry:
test1, 1400
Then file2 would have:
test1, 2400
As all of these files are generated by different programs, is it possible to check through each text file for a similar entry, for instance using the files mentioned above, say I wanted to find test1 from both files and calculate the sum of the score and thus get the following data saved to another text file:
test1, 3800
The Programming Language I am using is VB.NET, currently I have read all of the files using:
Dim Array1() As String = IO.File.ReadAllLines("path")
My current logic is to get all of the data into a list or a KeyValuePair, where the list will store the username of the user as well with their score which would be summed at this point. I have currently read all of the data from each text file to an array, with each array in the FormLoad Event I have got it into a form where the data is split with a delimiter with the comma. At the start of the program I have an Input Box which asks the user for their Username and stores it in a variable called UserInput. From there this is what I need help achieving, I need the Program to get value from each array and store it in another array where it sorts the data of each user with their scores, from their I can use: For i = 0 to ar.length - 1 Loop to go through the array and search for the Users username.
You can use the following approach
Dim arr1 As New List(Of String)
arr1.AddRange(IO.File.ReadAllLines("text file 1"))
Dim arr2 As New List(Of String)
arr2.AddRange(IO.File.ReadAllLines("text file 2"))
Dim searchstring As String = "test1"
'You can replace test1 with the string you are searching the text file for
Dim index1 As Integer = 0
Dim index2 As Integer = 0
'Getting the index of the string in the list
'*******************************************
For x As Integer = 0 To arr1.Items.Count - 1
If arr1(x).StartsWith(searchstring) Then
index1 = x
End If
Next
For x As Integer = 0 To arr2.Items.Count - 1
If arr2(x).StartsWith(searchstring) Then
index2 = x
End If
Next
'*******************************************
Dim split1() As String = Split(arr1(index1), ",")
Dim split2() As String = Split(arr2(index2), ",")
Dim sum As Integer = Integer.Parse(Trim(split1(1))) + Integer.Parse(Trim(split2(1)))
'Writing the sum to another test file, the "output.txt" file would be created on your desktop, you can replace the path's string with your custom location
Dim path As String = Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "output.txt")
Dim finaltext As String = searchstring + "," + sum.ToString
System.IO.File.AppendAllLines(path, finaltext)
The above method creates a new text file "output.txt" on your desktop.
AJD is correct. You need to make an attempt before posting. I answered because I want practice with Linq. Since you have 2 different types of data, a class or a structure is in order (or use a database). I filled a list of the structure by splitting the lines into the string portion and integer portion; setting the properties of the structure. You can add as many files as you wish to the List. I tested with both the Linq method and the Loop method.
Structure TestData
Public TestName As String
Public TestScore As Integer
End Structure
Private TestList As New List(Of TestData)
Private Sub AddToList(path As String)
Dim arr() As String = File.ReadAllLines(path)
For Each line As String In arr
Dim arr2() As String = line.Split(","c)
Dim td As TestData
td.TestName = arr2(0)
td.TestScore = CInt(arr2(1).Trim)
TestList.Add(td)
Next
End Sub
Private Function GetSummWithLinq(NameOfTest As String) As Integer
Dim result As Integer = (From Score In TestList
Where Score.TestName = NameOfTest
Select Score.TestScore).Sum
Return result
End Function
Private Function GetSumWithLoop(NameOfTest As String) As Integer
Dim total As Integer
For Each item In TestList
If item.TestName = NameOfTest Then
total += item.TestScore
End If
Next
Return total
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim p As String = "C:\Users\SomeUser\Desktop\TestData.txt"
AddToList(p)
Dim a As Integer = GetSummWithLinq("test1")
MessageBox.Show($"The Linq method produces {a}")
Dim b As Integer = GetSumWithLoop("test1")
MessageBox.Show($"The Loop method produces {b}")
End Sub
EDIT
My TestData.txt file that I used to test the code.
test1, 314
test2, 740
test1, 700
test2, 200
I am trying to order the largest scores in a file that is loaded into an array. Currently, the program opens the file, then reads it and then splits up each line into two parts - a name and a score; then stores that in an array. I am not sure how I can sort the array to find the largest 10 scores and put that into a listbox. At the moment, the program finds any scores above 0 and puts it in the listbox
Dim FileNum As Integer = FreeFile()
FileOpen(FileNum, "GameResultsFile", OpenMode.Input)
For index = 0 To 99
Dim temp() As String = LineInput(FileNum).Split(",") 'CUTTING LINE INTO TWO SECTIONS
MemoryGame.HighScores(index).Name = temp(0) 'NAME (First Part of Line)
MemoryGame.HighScores(index).Score = temp(1) 'SCORE (Second Part of Line)
If temp(1) > 0 Then 'If any of the scores is above 0 then
ListBox1.Items.Add(temp(0) + " " + temp(1)) ' display the name of the person who got that score and their score
End If
Next
FileClose()
Comments and explainations in line
'Note Imports System.IO
Structure Player
Public Score As Integer
Public Name As String
'Added a constructor to the structure to make it easy to add new Player
Public Sub New(myScore As Integer, myName As String)
Score = myScore
Name = myName
End Sub
End Structure
Private HighScores(99) As Player
Private index As Integer 'used in both LoadArray and SortAndDisplayArray
Private Sub LoadArray()
Using sr As New StreamReader("GameResultsFile.txt")
Dim line As String
Do While sr.Peek() > -1 'Peek checks if there is another character in the file
line = sr.ReadLine()
Dim temp() As String = line.Split(","c) 'CUTTING LINE INTO TWO SECTIONS
'Notice the elements of the temp array are switched to match the
'Player constructor (Sub New)
HighScores(index) = New Player(CInt(temp(1)), temp(0))
index += 1 'not only keeps track of the index but remembers how many elements
'we have added to HighScores
Loop
End Using
End Sub
Private Sub SortAndDisplayArray()
'This is the LINQ way to do it, you can do a great deal in one line of code
'There is a loop underneath but you don't have to write it.
'I added a Take clause so we will not get a bunch of 0- in the list box going up to index 99
' You might want to show, for example only the top ten scorers, so change to Take 10
Dim orderArray = From scorer In HighScores Order By scorer.Score Descending Select $"{scorer.Score} - {scorer.Name}" Take index
ListBox1.DataSource = orderArray.ToList
End Sub
I still think a List(Of T) would be easier but I have a feeling your assignment requires you to use an array.
I'd do it something like this using IComparable
First I would load the data from your text file like so and save the data to a List Of and the Type would be the Player class down below.
'' Get Data From Text File And Create An Anonymous Type
Private Sub LoadPlayerAndScore(path As String)
'' Load data from text file
Dim data = From line In System.IO.File.ReadAllLines(path)
Let val = line.Split(",")
Select New With {Key .Name = val(0), Key .Score = val(1)}
'' Save data to list
For Each pair In data
Dim player As New Player With {
.Name = pair.Name,
.Score = pair.Score
}
playersList.Add(player)
Next
End Sub
I would then go on to create a player class which will Implement the ICompareble listed above.
Class Player
Implements IComparable(Of Player)
Public Property Name As String
Public Property Score As Integer
Public Sub Player(ByVal name As String, ByVal score As Integer)
Me.Name = name
Me.Score = score
End Sub
'' Sort Player From The Hightest Score To The Lowest Score
Private Function IComparable_CompareTo(other As Player) As Integer Implements IComparable(Of Player).CompareTo
Return other.Score.CompareTo(Me.Score)
End Function
End Class
I would then create some public variables such as
Dim playersList As New List(Of Player)
Dim fileLocation As String = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Settings.txt")
Change the path to your file's location.And finally in a Form Load Event I would call it all like this
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
'' Load Data From Text File On Desktop
LoadPlayerAndScore(path:=fileLocation)
'' Sort List
playersList.Sort()
'' Add Values To List
For Each p As Player In playersList
ListBox1.Items.Add("Name: " + p.Name + " Score: " + p.Score.ToString())
Next
End Sub
Here is what the code should look something like altogether
Public Class Form1
Dim playersList As New List(Of Player)
Dim fileLocation As String = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Settings.txt")
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
'' Load Data From Text File On Desktop
LoadPlayerAndScore(path:=fileLocation)
'' Sort List
playersList.Sort()
'' Add Values To List
For Each p As Player In playersList
ListBox1.Items.Add("Name: " + p.Name + " Score: " + p.Score.ToString())
Next
End Sub
'' Get Data From Text File And Create An Anonymous Type
Private Sub LoadPlayerAndScore(path As String)
'' Load data from text file
Dim data = From line In System.IO.File.ReadAllLines(path)
Let val = line.Split(",")
Select New With {Key .Name = val(0), Key .Score = val(1)}
'' Save data to list
For Each pair In data
Dim player As New Player With {
.Name = pair.Name,
.Score = pair.Score
}
playersList.Add(player)
Next
End Sub
End Class
Class Player
Implements IComparable(Of Player)
Public Property Name As String
Public Property Score As Integer
Public Sub Player(ByVal name As String, ByVal score As Integer)
Me.Name = name
Me.Score = score
End Sub
'' Sort Player From The Hightest Score To The Lowest Score
Private Function IComparable_CompareTo(other As Player) As Integer Implements IComparable(Of Player).CompareTo
Return other.Score.CompareTo(Me.Score)
End Function
End Class
Here is the output I gotAnd here is what the text files data looked like.
ANDREW,25
MERVE,12
RUZGAR,50
And for the top ten people, follow the comments above.
How about try this?
Dim sortedArray = _
File _
.ReadAllLines("GameResultsFile") _
.Select(Function (line) line.Split(","c)) _
.Select(Function (parts) New With { .Name = parts(0), .Score = Integer.Parse(parts(1)) }) _
.OrderByDescending(Function (x) x.Score) _
.Select(Function (x) x.Name & " " & x.Score)
.ToArray()
For Each item As String In sortedArray
ListBox1.Items.Add(item)
Next
I'm using VB.NET 2010 and have been trying to wrap my head around implementing a search feature using a sequential file. Originally I was trying to use a sequential file to read from and search but that has proven to be extremely difficult so I've taken a simple approach using two different arrays with data and try to search through Artist and Album.
The code below takes input from txtSearch.Text which will be for search by artist. I have a duplicate artist "TeeBee" but when I search for that artist I only receive one result instead of two as there are two different albums under the artist "TeeBee".
I thought about adding another loop but it doesn't work. I also thought that the results were getting cut off as there isn't a way to add a return to the results to continue on.
I'm a beginner to programming so please keep that in mind.
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
' Artist array
Dim strArtist() As String = {"Dillinja", "TeeBee", "Dieselboy", "TeeBee"}
' Album array
Dim strAlbum() As String = {"Untitled", "Scorpion", "Horns", "Blades"}
Dim strSearchForArtist As String
Dim intSub As Integer
' artist search
strSearchForArtist = txtSearch.Text
Do Until intSub = strAlbum.Length OrElse
strSearchForArtist = strArtist(intSub)
intSub = intSub + 1
Loop
If intSub < strArtist.Length Then
lstLibrary.Items.Add(strArtist(intSub) & " " & strAlbum(intSub) & vbNewLine)
Else
MessageBox.Show("Invalid", "Bad", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
End Sub
Attempt to load text file into array but it doesn't create separate arrays like album, artist genre. - 11-19-14
Private Sub btnLoadArray_Click(sender As Object, e As EventArgs) Handles btnLoadArray.Click
Dim filePath As String = "library.txt"
Dim sr As IO.StreamReader
sr = IO.File.OpenText(filePath)
' look inside file and read every line
' this will be how we put the number for
' our array below
Dim TotalLines As Integer = 0
Dim word As String = ""
' need 3 to be dynamic so we get all lines in the file to build the array words(#)
' wanted to use words(,) but that does not work
Dim words() As String = IO.File.ReadAllLines(filePath)
Dim i As Integer = 0
' when the peak value is -1 we're at the end of the file
Do Until sr.Peek = -1
' load one at a time
word = sr.ReadLine()
' load word into array
words(i) = word
' output
lstArtist.Items.Add(words(i))
' increment counter
i += 1
Loop
'close the file
sr.Close()
End Sub
Well, instead of using arrays and handle all the complications I really suggest you to have a more object oriented approach
So start defining a class to keep the info for an Album like this
Public Class Album
Public ArtistName as String
Public AlbumTitle as String
Public Function ToString() as String
return ArtistName & " - " & AlbumTitle
End Function
End Class
Now you could remove the array mess using a List(Of Album) and asking to each item of this list to render its content via the ToString method.
Also an important role here is reserved to the IEnumerable function Where that extract from the List(Of Album) all the elements that respects the Lambda expression required by the Where method.
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
' Here the list is fixed but you can easily build it loading data from a database
' or from some other storage medium like a file etc...
Dim albumList = new List(Of Album) From _
{
new Album With { .ArtistName = "Dillinja", .AlbumTitle = "Untitled" },
new Album With { .ArtistName = "TeeBee", .AlbumTitle = "Scorpion"},
new Album With { .ArtistName = "Dieselboy", .AlbumTitle = "Horns" },
new Album With { .ArtistName = "TeeBee", .AlbumTitle = "Blades" }
}
' To help search you could integrate the ToLower expressions in
' Plutonix answer here...
Dim searchTerm = txtSearch.Text
Dim searchResult = albumList.Where(Function(x) x.ArtistName = searchTerm)
lstLibrary.Items.Clear()
if searchResult.Count > 0 Then
For Each item in searchResult
lstLibrary.Items.Add(item.ToString())
Next
Else
MessageBox.Show("Not found")
End if
End Sub
Rather than arrays, a List(of String) is easier to manage and provides more efficiency and the kind of functions you probably want.
Private Artists As New List(of String)
....
Artists.Addrange({"Dillinja", "TeeBee", "Dieselboy", "TeeBee"})
...
' find a single item:
If Artists.Contains(txtSearch.Text) Then ' no looping required
' a dupe
Else
' not a dupe
End If
To get all the matching items:
Dim find = Artists.Where(Function(s) _
s.ToLowerInvariant = txtSearch.Text.ToLowerInvariant).ToList
The resulting find will also be a List(of String) containing the matching item. This time it is case insensitive. To get the count of dupes:
Dim finds = Artists.LongCount(Function(n) n.ToLowerInvariant = _
txtSearch.Text.ToLowerInvariant.ToLowerInvariant)
I dont know how much value either can be. Neither 2 nor a List of "Teebee", "TeeBee" is very useful or interesting. More typically, you want the return to be the entire object (like an album) associated with the search term. This requires a Class which glues Arist, Album, Genere, Tracks etc together though (see Steve's answer for a start on this part).
As for the whole file part, the list(s) can be easily serialized allowing an entire list to be saved or reloaded from disk in 2-3 lines of code.