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
Related
For my Visual Basic final, my program is required to read data from a text file into two different arrays, each being one-dimensional. The following is my code for doing so:
Option Explicit On
Option Infer Off
Option Strict On
Public Class frmMain
'Constant for filename and a dirty flag variable
Const INVENTORY_FILENAME As String = "inventory.txt"
Dim noFile As Boolean = False
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Populates DVD listbox with text file data upon load
'Variable for reading the file
Dim myFile As IO.StreamReader
'Declaring arrays for DVD names and prices
Dim arrayDVD() As String
Dim arrayPrice() As Double
'Variables for populating arrays with respective data
Dim dvdName As String
Dim dvdPrice As Double
Dim i As Integer = 0
'Checking that file exists then reading data to each array
If IO.File.Exists(INVENTORY_FILENAME) Then
myFile = IO.File.OpenText(INVENTORY_FILENAME)
'Read data to arrays
Do Until myFile.Peek = -1
dvdName = myFile.ReadLine()
dvdPrice = Double.Parse(myFile.ReadLine())
arrayDVD = dvdName
arrayPrice = dvdPrice
'Using arrays to populate multicolumn listbox
lstDVD.Items.Add(arrayDVD(i) & arrayPrice(i))
i += 1
Loop
'Closing the file
myFile.Close()
End If
End Sub
End Class
The text file alternates names and prices of DVDs to be read as individual lines, making the arrays parallel:
Pulp Fiction
9.99
Jumanji
13.99
And so on...
I'm receiving a value type error code stating that I cannot convert 'String' to 'String()' or convert 'Double' to 'Double()' when setting the arrays' values equal to their respective variables. Is there a way to correct this? Thanks in advance!
These lines are wrong:
arrayDVD = dvdName
arrayPrice = dvdPrice
arrayDVD and arrayPrice are arrays. You need to assign to a specific element in each of those arrays:
arrayDVD(i) = dvdName
arrayPrice(i) = dvdPrice
Don't forget to make sure the arrays actually have enough elements for this.
Hint: ReDim Preserve is pretty much the least efficient way possible to make sure an array is big enough. Each use will allocate a brand new array, copy the elements one at a time, assign the new array to the old reference, and then release the old array. It does not preserve in-place. Nevertheless, if this is a 100-level course it might be what you are expected to do at this point.
Finally, you should never use Double when working with money (use Decimal instead).
Separate from the question, here is how I might approach this without the weird array limitation:
Private Iterator Function ReadInventoryFile(filePath As String) As IEnumerable(Of (String, Decimal))
Using rdr As New StreamReader(filePath)
Dim DVDName As String = Nothing
While (DVDName = rdr.ReadLine()) IsNot Nothing
Yield (DVDName, Decimal.Parse(rdr.ReadLine()))
End While
End Using
End Function
Const INVENTORY_FILENAME As String = "inventory.txt"
Private data As List(Of (String, Decimal))
Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try 'Replaces the File.Exists() check
data = ReadInventoryFile(INVENTORY_FILENAME).ToList()
For Each item As (String, Decimal) In data
lstDVD.Items.Add($"{item.Item1}{vbTab}{item.Item2:C}")
Next
Catch
' Actually do something here. Empty catch blocks are rarely correct.
' Note I catch at this level, rather than in the ReadFile() method.
End Try
End Sub
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'm an extreme beginner with vb and coding in general and this is my first post on this site. I am running into a wall with a project I am working on. This is the smallest block of code in the project but all other functions will pull from the array I'm trying to populate. Essentially I need to populate an array with numbers representing the prices of DVDs from a .txt file. The .txt file is formatted as follows:
The Lord of the Rings, 10.50
Avatar, 5
Gangs of New York, 7.5
etc
Where 10.50 is the value I would want to assign to dblPrices(0). It is required to not change the format of the .txt file. So far, this is what I was using but when testing the output I'm getting back 0's:
'Declare variables.
Dim intCount As Integer = 0
Dim strLine As String
'Open the file for input.
inFile = IO.File.OpenText("availableDVDs.txt")
'Remove alpha characters from string, assign numeric values to array representing price.
Do Until inFile.Peek = -1
strLine = inFile.ReadLine.ToUpper.Replace("[A-Z]", "")
strLine = strLine.Replace(" ", "")
strLine = strLine.Replace(",", "")
Double.TryParse(strLine, dblPrices(intCount))
intCount += 1
Loop
This is related to a school project so I'm not necessarily looking for someone to do my work for me, but perhaps point me in the right direction. Thank you!
If you use List(Of T) (The T stands for Type, like Integer or String or your own type) then you don't need to know the size in advance like an array. Also you don't need to keep track of indexes. You can just use the .Add method and the new item is put at the end of the list.
You can get a head start on getting the data out of the file by using File.ReadAllLines which will return an array of lines in the text file. Then you can just .Split each line on the "," (comma) and use the second element of the resulting array. The little c after the comma in double quotes tells the compiler that you mean this a Char which is the datatype that .Split is expecting.
I used a Decimal datatype instead of Double. When working with money it is safer to use to get the answer you expect.
In the second code sample I used an Interpolated sting indicated by the $ preceding the string. Notice that it is very similar to String.Format only the variable is inserted directly in the braces instead of a placeholder. This is available in Visual Studio 2015 and later.
The array method...
Private Sub OPCode()
Dim Lines = IO.File.ReadAllLines("availableDVDs.txt")
Dim Prices(Lines.Count - 1) As Decimal
Dim index As Integer
Dim price As Decimal
For Each line In Lines
Dim SplitOnComma = line.Split(","c)
If Decimal.TryParse(SplitOnComma(1), price) Then
Prices(index) = price
index += 1
Else
MessageBox.Show(String.Format("Price for {0} is not valid.", SplitOnComma(0)))
End If
Next
End Sub
The list method...
Private Sub UsingList()
Dim Lines = IO.File.ReadAllLines("availableDVDs.txt")
Dim Prices As New List(Of Decimal)
Dim price As Decimal
For Each line In Lines
Dim SplitOnComma = line.Split(","c)
If Decimal.TryParse(SplitOnComma(1), price) Then
Prices.Add(price)
Else
MessageBox.Show($"Price for {SplitOnComma(0)} is not valid.")
End If
Next
End Sub
With Option Infer Off
Private Sub OPCode()
Dim Lines() As String = IO.File.ReadAllLines("availableDVDs.txt")
Dim Prices(Lines.Count - 1) As Decimal
Dim index As Integer
Dim price As Decimal
For Each line In Lines
Dim SplitOnComma() As String = line.Split(","c)
If Decimal.TryParse(SplitOnComma(1), price) Then
Prices(index) = price
index += 1
Else
MessageBox.Show(String.Format("Price for {0} is not valid.", SplitOnComma(0)))
End If
Next
End Sub
The objective of the program is to interpret hockey statistics from a file using StreamReader and then display an added column of points. The following code kinda does so, however it’s ineffective in the sense that it doesn’t add the points value to the array - it separately outputs it. Looking for assistance as to how it would be possible to incorporate the points value into aryTextFile();
Dim hockeyFile, LineOfText, aryTextFile() As String
Dim i As Integer
Dim nameText(), NumberText(), goalsText(), assistsText(), GamesWonText() As String
Dim IntAssists(), IntGoals(), PointsText() As Single
hockeyFile = "C:\Users\Bob\Downloads\hockey.txt" 'state location of file
Dim objReader As New System.IO.StreamReader(hockeyFile) 'objReader can read hockeyFile
For i = 0 To objReader.Peek() <> -1 'reads each line seperately, ends when there is no more data to read
LineOfText = objReader.ReadLine 'stores seperate lines of data in HockeyFile into LineofText
aryTextFile = LineOfText.Split(",") 'takes lines and converts data into array
Name = aryTextFile(0) 'first piece of data in lines of text is the name
nameText(i) = aryTextFile(0)
If nameText(0) = "Name" Then
TextBox1.Text = LineOfText & ", Points." & vbCrLf 'displays first line fo text and adds "Points" label
End If
If Name <> "Name" Then 'when second line starts, then begin to intepret data
NumberText(i) = aryTextFile(1)
assistsText(i) = aryTextFile(2) 'assists are in third value of array
goalsText(i) = aryTextFile(3) 'goals are in fourth value of array
GamesWonText(i) = aryTextFile(4)
IntAssists(i) = Val(assistsText(i)) 'since our assists value is a string by default, it must be converted to a integer
IntGoals(i) = Val(goalsText(i)) 'since our goals value is a string by default, it must be converted to a integer
PointsText(i) = (IntGoals(i) * 2) + (IntAssists(i)) 'goals are two points, assists are one point
TextBox1.Text = TextBox1.Text & NumberText(i) & assistsText(i) & goalsText(i) & GamesWonText(i) & PointsText(i) & vbCrLf 'Displays points as last value in each line
End If
Next i
This should get you pretty close:
It'll need extra validation. It doesn't take into account whatever value you have between the name and the goals.
Private Sub ProcessHockeyStats()
Try
Dim inputFile As String = "c:\temp\hockey.txt"
Dim outputFile As String = "c:\temp\output.txt"
If Not File.Exists(inputFile) Then
MessageBox.Show("Missing input file")
Return
End If
If File.Exists(outputFile) Then
File.Delete(outputFile)
End If
Dim lines() As String = File.ReadAllLines(inputFile)
Dim output As List(Of String) = New List(Of String)
Dim firstLine As Boolean = True
For Each line As String In lines
Dim values() As String = line.Split(","c)
Dim points As Integer
If firstLine Then
output.Add("Name, Assists, Goals, Points")
firstLine = False
Else
'needs validation for values
points = CInt(values(1) * 2) + CInt(values(2))
output.Add(String.Concat(line, ",", points))
End If
Next
File.WriteAllLines("c:\temp\outfile.txt", output)
Catch ex As Exception
MessageBox.Show(String.Concat("Error occurred: ", ex.Message))
End Try
End Sub
VS2008 is ancient, especially when later versions of Visual Studio are free. I felt like showing an implementation using more-recent code. Like others, I strongly support building a class for this. The difference is my class is a little smarter, using the Factory pattern for creating instances and a Property to compute Points as needed:
Public Class HockeyPlayer
Public Property Name As String
Public Property Number As String
Public Property Assists As Integer
Public Property Goals As Integer
Public Property Wins As Integer
Public ReadOnly Property Points As Integer
Get
Return (Goals * 2) + Assists
End Get
End Property
Public Shared Function FromCSVLine(line As String) As HockeyPlayer
Dim parts() As String = line.Split(",")
Return New HockeyPlayer With {
.Name = parts(0),
.Number = parts(1),
.Assists = CInt(parts(2)),
.Goals = CInt(parts(3)),
.Wins = CInt(parts(4))
}
End Function
End Class
Dim hockeyFile As String = "C:\Users\Bob\Downloads\hockey.txt"
Dim players = File.ReadLines(hockeyFile).Skip(1).
Select(Function(line) HockeyPlayer.FromCSVLine(line)).
ToList() 'ToList() is optional, but I included it since you asked about an array
Dim result As New StringBuilder("Name, Number, Assists, Goals, Wins, Points")
For Each player In players
result.AppendLine($"{player.Name}, {player.Number}, {player.Assists}, {player.Goals}, {player.Wins}, {player.Points}")
Next player
TextBox1.Text = result.ToString()
I was gonna give you VS 2008 version afterward, but looking at this, the only thing here you couldn't do already even by VS 2010 was string interpolation... you really should upgrade.
Parallel arrays are really not the way to handle this. Create a class or structure to organize the data. Then create a list of the class. The list can be set as the DataSource of a DataGridView which will display your data in nice columns with headings matching the names of your properties in the Hockey class. You can easily order your data in the HockeyList by any of the properties of Hockey.
Public Class Hockey
Public Property Name As String
Public Property Number As String
Public Property Goals As Integer
Public Property Assists As Integer
Public Property Points As Integer
Public Property GamesWon As Integer
End Class
Private HockeyList As New List(Of Hockey)
Private Sub FillListAndDisplay()
Dim path = "C:\Users\Bob\Downloads\hockey.txt"
Dim Lines() = File.ReadAllLines(path)
For Each line As String In Lines
Dim arr() = line.Split(","c)
Dim h As New Hockey()
h.Name = arr(0)
h.Number = arr(1)
h.Assists = CInt(arr(2).Trim)
h.Goals = CInt(arr(3).Trim)
h.GamesWon = CInt(arr(4).Trim)
h.Points = h.Goals * 2 + h.Assists
HockeyList.Add(h)
Next
Dim orderedList = (From scorer In HockeyList Order By scorer.Points Ascending Select scorer).ToList
DataGridView1.DataSource = orderedList
End Sub
I'm working on a project, for school, that reads text from a .txt file to an array. After doing that, I'm supposed to sort the array, alphabetically, and then list the contents in a listbox. Here is my code:
Imports System.IO
Public Class Form1
'Allow array to be accessed by the entire program
Public books(1) As String
Private Sub btnView_Click(sender As Object, e As EventArgs) Handles btnView.Click
'Declare variables
Dim sr As New StreamReader("C:\Users\Bryson\Desktop\BooksinStock.txt")
Dim book As String
Dim i As Integer = 0
'Establish loop to read contents of the text file into the array and list the array in the listbox
'the sr.Peek = -1 simply means that the reader has reached the end of the file and there is nothing more to be read
Do Until sr.Peek = -1
book = sr.ReadLine()
'ReDim allows the array to grow with the set amount of books in text file
ReDim books(books.Length + 1)
books(i) = book
i += 1
Loop
Array.Sort(books)
lstBoxInventory.Items.Add(books(i))
End Sub
End Class
However, when I run the program, I receive an error on the lstBoxInventory.Items.Add(books(i)) line that says "an unhandled exception of the type 'System.ArgumentNullException' occurred in System.Windows.Forms.Dll
I've tried to lay the code out in various ways to get the sort to work but keep coming up short. Does anyone know how to get rid of this null error?
The problem happening because "i" is larger than the highest index
Do Until sr.Peek = -1
book = sr.ReadLine()
ReDim books(books.Length + 1)
books(i) = book
i += 1 'This is adding 1 to the very end
Loop
Array.Sort(books)
lstBoxInventory.Items.Add(books(i)) 'When the items are being added it is trying to add an extra i that does not exist
edit
Honestly I would change the format to use ReadAllLines and list(of String)
Something like (Im writing code from memory)
Dim bookList as new List(of String)
Dim bookTextFile as String() = File.ReadAllLines("C:\booklist.txt")
for each book as String in bookTextFile
bookList.add(book)
next
bookList.Sort
Edit Again
Just using this
Dim bookList As String() = System.IO.File.ReadAllLines("C:\Users\Bryson\Desktop\BooksinStock.txt")
creates a single dimension array ..
Strings() are single Arrays String(,) are two dimensional Arrays
Honestly your whole homework could be
Dim bookList As String() = System.IO.File.ReadAllLines("C:\Users\Bryson\Desktop\BooksinStock.txt")
Array.Sort(BookList)
boom - done.
Test it using
for each book as String in BookList
Msgbox(book)
next
You could do
Dim bookList As String() = System.IO.File.ReadAllLines("C:\Users\Bryson\Desktop\BooksinStock.txt")
Dim books(bookList.Length - 1) As String 'This is the same as ReDim
For x As Integer = 0 To bookList.Length - 1
books(x) = bookList(x)
Next
Array.Sort(books)
but you would literally be saying bookList = books
But.... if you just want to get your code working, just try this
lstBoxInventory.Items.Add(books(i -1)) 'This takes away the extra i that you added