Populating an array from an input file - arrays

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

Related

Search Multiple Text Files for Similar Data

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

VB Convert 2 DataRows to a Single String in an Array

My Goal is to take two rows(FirstName and Surname) Convert them to a single Array of "FirstName, Surname".
This is my terrible code i eventually put together
Private Sub Search_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'DbaPatientDataSet.tblPatientData' table. You can move, or remove it, as needed.
Me.TblPatientDataTableAdapter.Fill(Me.DbaPatientDataSet.tblPatientData)
listFirst.DataSource = Me.TblPatientDataBindingSource
listFirst.DisplayMember = "FirstName"
listLast.DataSource = Me.TblPatientDataBindingSource
listLast.DisplayMember = "Surname"
Dim Lenth As Integer = Me.listFirst.Items.Count - 1
Dim count As Integer = 1
Dim ArrFirst(Lenth) As String
Dim ArrLast(Lenth) As String
For count = 1 To Lenth
ArrFirst(count) = listFirst.Items(count).ToString
ArrLast(count) = listLast.Items(count).ToString
Next count
count = 1
For count = 1 To Lenth
arrFullName(count) = ArrLast(count) & ", " & ArrFirst(count)
Next count
'Arrays Set =====================================================
But with this code i get an Array of
`"Sytem.Data.DataRowView, Sytem.Data.DataRowView"
"Sytem.Data.DataRowView, Sytem.Data.DataRowView"
"Sytem.Data.DataRowView, Sytem.Data.DataRowView"
"Sytem.Data.DataRowView, Sytem.Data.DataRowView"
`
As you can see
Here
There must be an easy way to convert both DataRows to strings then concatenate them together in an array
I am going to search this array using a Binary Search to find a desired name
Thanks
First, I think you are confusing your rows and your columns. You have 2 columns. I went directly to full name but I think you can break it out if you need to.
Dim arrNames(ListBox1.Items.Count - 1) As String
For i As Integer = 0 To ListBox1.Items.Count - 1
arrNames(i) = $"{ListBox1.Items(i)} {ListBox2.Items(i)}"
Next
For Each item In arrNames
Debug.Print(item)
Next
The string with the $ in front is an interpolated string. Sort of an improvement to String.Format.
I know there is an answer but for now you could go direct to the data table to get what you need.
Dim arrNames(ListBox1.Items.Count - 1) As String
Dim i As Integer = 0
Dim dt As DataTable = DbaPatientDataSet.Tables(0)
For Each row As DataRow In dt.Rows
arrNames(i) = $"{row("Surname")}, {row("FirstName")}"
i += 1
Next
For Each item In arrNames
Debug.Print(item)
Next
'assume the names of your columns are Surname and FirstName
If I run your code up, I get the result you are looking for, so I'm not sure what you are missing. In saying that though, you are making things hard on yourself by messing around with arrays :). Just use the dataset rows directly - they are strongly typed and you can check for nulls etc as needed... something like this;
Dim fullNames As New List(Of String) '-- or you could fill your array.
For Each row As DbaPatientDataSet.tblPatientDataRow In ds.tblPatientData
fullNames.Add(row.Surname & ", " & row.FirstName)
Next
Just looking at what you are trying to achieve, if it was me, I would be bringing back the formatted data in my query that fills the dataset i.e. a third, FullName, column.
It has been in the back of my mind. Finally got it for the List Box directly.
Dim arrFullNames(ListBox1.Items.Count - 1) As String
Dim i As Integer = 0
For Each item As DataRowView In ListBox1.Items
arrFullNames(i) = $"{DirectCast(item("Surname"), String)}, {DirectCast(item("Firstname"), String)}"
i += 1
Next
For Each item As String In arrFullNames
Debug.Print(item)
Next

Sum and Average in a txt file array VBA

I'm trying to display an average from a txt file that has both restaurant names and net worth in a list. I'm displaying it in a label. I'm still learning Visual Basic, so I'm not even sure if my code is just a bunch of garbage. Here's what I've got. Not only is it not displaying anything, but it also has an error
"Structure "Integer" cannot be indexed because it has no default
value"
for intNumber. Here's what I have:
Private Sub btnCompute_Click(sender As Object, e As EventArgs) Handles
btnCompute.Click
Dim objReader As IO.StreamReader
Dim strLocationAndNameOfFile As String = "I:\franchise.txt"
Dim IntTotal As Integer
Dim intNumber As Integer
Dim intElement As Integer
Dim intAverage As Integer
Dim intCount As Integer = 10
If IO.File.Exists(strLocationAndNameOfFile) Then
objReader = IO.File.OpenText(strLocationAndNameOfFile)
For Each intElement In intNumber(strLocationAndNameOfFile)
IntTotal += intElement
Next
intAverage = IntTotal / intCount
lblAverageCost.Text = intAverage.ToString("C")
End If
End Sub
Although you are opening the text file, you're not actually reading it. Also there are a few slightly different ways I'd do things - have a look at the code an comments.
Dim strLocationAndNameOfFile As String = "I:\franchise.txt"
Dim IntTotal As Integer
Dim intAverage As Integer
Dim intNumberCount As Integer
'Use a string array to store the file contents
'instead of using a separate intElements variable (which btw you defined as an individual
'integer instead of an array, just use the string array to store the text of the file
'without also having to use an integer array. In the loop below, each element of the string
'array is parsed into an integer as needed, so no need for an extra array
Dim fileLines() As String
If IO.File.Exists(strLocationAndNameOfFile) Then
'The using statement opens the file and the end using statement will close the file and
'dispose of the sr object. Its important to close a file when you're done using it
Using sr As New StreamReader(strLocationAndNameOfFile)
'This line does three things. .ReadToEnd reads all the lines in the file and then splits the
'lines into individual strings. I'm assuming that the lines end with a VbCrLf and not a VbCr
'Finally those individual lines are stored in the string array
fileLines = sr.ReadToEnd.Split(vbCrLf)
'file is closed here and the sr object is disposed
End Using
'Here the code loops through each element of fileLines and trys to parse them into an integer and
'assin the integer to intNumber. If successful, the number is added to the total and 1 is added to
'intNumberCount to keep track of the number of successfully parsed numbers
For Each line As String In fileLines
Dim intNumber As Integer
If Integer.TryParse(line, intNumber) Then
IntTotal += intNumber
intNumberCount += 1
End If
Next
'finally the average is calculated
intAverage = IntTotal / intNumberCount
lblAverageCost.Text = intAverage.ToString("C")
End If

Fastest way to compare a large amount of text against 125,000 database records

The aim of my application is to extract text from documents and search for specific entries matching records in a database.
My application extracts text from documents and populates a textbox
with the extracted text.
Each document can have anywhere from 200 to 600,000 words
(including a large amount of normal plain text).
Extracted text is compared against database entries for specific
values and matches are pushed into an array.
My Database contains approximately 125,000 records
My code below loops through the database records, comparing against the extracted text. If a match is found in the text it is inserted into an array which I use later.
txtBoxExtraction.Text = "A whole load of text goes in here, " & _
"including the database entries I am trying to match," & _
"i.e. AX55F8000AFXZ and PP-Q4681TX/AA up to 600,000 words"
Dim dv As New DataView(_DBASE_ConnectionDataSet.Tables(0))
dv.Sort = "UNIQUEID"
'There are 125,000 entries here in my sorted DataView dv e.g.
'AX40EH5300
'GB46ES6500
'PP-Q4681TX/AA
For i = 0 to maxFileCount
Dim path As String = Filename(i)
Try
If File.Exists(path) Then
Try
Using sr As New StreamReader(path)
txtBoxExtraction.Text = sr.ReadToEnd()
End using
Catch e As Exception
Console.WriteLine("The process failed: {0}", e.ToString())
End Try
end if
For dvRow As Integer = 0 To dv.Table.Rows.Count - 1
strUniqueID = dv.Table.Rows(dvRow)("UNIQUEID").ToString()
If txtBoxExtraction.Text.ToLower().Contains(strUniqueID.ToLower) Then
' Add UniqueID to array and do some other stuff..
End if
next dvRow
next i
Whilst the code works, I am looking for a faster way of performing the database matching (the 'For dvRow' Loop).
If a document is small with around 200 words, the 'For dvRow..' Loop completes quickly, within a few seconds.
Where the document contains a large amount of text... 600,000 words and upwards, it can take several hours or longer to complete.
I came across a couple of posts that are similar, but not close enough to my issue to implement any of the recommendations.
High performance "contains" search in list of strings in C#
https://softwareengineering.stackexchange.com/questions/118759/how-to-quickly-search-through-a-very-large-list-of-strings-records-on-a-databa
Any help is most gratefully appreciated.
This is an example of the comment a wrote.
If that's the actual code, I don't understand why you need to put the
information in a textbox. You could save a bit of speed by not
displaying the text on screen. If you have 125000 UNIQUEIDs, then it
might be better to pull the id from your file and then search from
that list. Instead of searching the whole text every time. Even just
splitting your text by space and filtering by the "words" that are
between a specific size could make it go faster.
Since it seems you want to do a word check and not a per-character check. And that you only want to check for those ids and not each word. You should pull up the ids from each text before doing any search. This will reduce the searching that need to be done by a lot. This list of id could also be saved if the text never changes.
Module Module1
Private UNIQUEID_MIN_SIZE As Integer = 8
Private UNIQUEID_MAX_SIZE As Integer = 12
Sub Main()
Dim text As String
Dim startTime As DateTime
Dim uniqueIds As List(Of String)
text = GetText()
uniqueIds = GetUniqueIds()
'--- Very slow
startTime = DateTime.Now
' Search
For Each uniqueId As String In uniqueIds
text.Contains(uniqueId)
Next
Console.WriteLine("Took {0}s", DateTime.Now.Subtract(startTime).TotalSeconds)
'--- Very fast
startTime = DateTime.Now
' Split the text by words
Dim words As List(Of String) = text.Split(" ").ToList()
' Get all the unique key, assuming keys are between a specific size
Dim uniqueIdInText As New Dictionary(Of String, String)
For Each word As String In words
If word.Length < UNIQUEID_MIN_SIZE Or word.Length > UNIQUEID_MAX_SIZE Then
If Not uniqueIdInText.ContainsKey(word) Then
uniqueIdInText.Add(word, "")
End If
End If
Next
' Search
For Each uniqueId As String In uniqueIds
uniqueIdInText.ContainsKey(uniqueId)
Next
Console.WriteLine("Took {0}s", DateTime.Now.Subtract(startTime).TotalSeconds)
Console.ReadLine()
End Sub
' This only randomly generate words for testing
' You can ignore
Function GetRandomWord(ByVal len As Integer) As String
Dim builder As New System.Text.StringBuilder
Dim alphabet As String = "abcdefghijklmnopqrstuvwxyz"
Dim rnd As New Random()
For i As Integer = 0 To len - 1
builder.Append(alphabet.Substring(rnd.Next(0, alphabet.Length - 1), 1))
Next
Return builder.ToString()
End Function
Function GetText() As String
Dim builder As New System.Text.StringBuilder
Dim rnd As New Random()
For i As Integer = 0 To 600000
builder.Append(GetRandomWord(rnd.Next(1, 15)))
builder.Append(" ")
Next
Return builder.ToString()
End Function
Function GetUniqueIds() As List(Of String)
Dim wordCount As Integer = 600000
Dim ids As New List(Of String)
Dim rnd As New Random()
For i As Integer = 0 To 125000
ids.Add(GetRandomWord(rnd.Next(UNIQUEID_MIN_SIZE, UNIQUEID_MAX_SIZE)))
Next
Return ids
End Function
End Module

Why Won't My Array Sort? (Visual Basic)

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

Resources