Split() doesn't work properly - vb.net

well I'm doing a computing assessment and well I've ran into an issue with splitting a string. For some reason when the string splits the array stores the whole thing in Variable(0). The error that occurs is when it tries to assign TicketID(Index) a value, it says that the array is out of bound.
Here's the code:
Private Sub ReadInformation(ByRef TicketID() As String, CustomerID() As String, PurchaseMethod() As Char, NumberOfTickets() As Integer, FileName As String)
Dim Line, TextArray(3) As String
Dim Index As Integer
FileOpen(1, FileName, OpenMode.Input)
For Index = 0 To 499
Input(1, Line)
TextArray = Line.Split(",")
CustomerID(Index) = TextArray(0)
TicketID(Index) = TextArray(1)
NumberOfTickets(Index) = TextArray(2)
PurchaseMethod(Index) = TextArray(3)
MessageBox.Show(CustomerID(Index))
Next
FileClose()
End Sub
Here's the first 10 lines of the TextFile I'm trying to read:
C001,F3,10,S
C002,F3,2,O
C003,F3,3,S
C004,W2,9,S
C005,T3,10,S
C006,F3,2,S
C007,W1,3,O
C008,W3,1,O
C009,T2,2,S
C010,F2,9,O
Here's the Error Message I receive:
Error Message

I would use some Lists instead of arrays. In this way you don't have to worry about length of the arrays or if there are fewer lines than 500. Of course, using the more advanced NET Framework methods of the File.IO namespace is a must
Private Sub ReadInformation(TicketID As List(Of String), _
CustomerID As List(Of String), _
PurchaseMethod As List(Of Char), _
NumberOfTickets As List(Of Integer), _
FileName As String)
for each line in File.ReadLines(FileName)
Dim TextArray = Line.Split(","c)
if TextArray.Length > 3 Then
CustomerID.Add(TextArray(0))
TicketID.Add(TextArray(1))
' This line works just because you have Option Strict Off
' It should be changed as soon as possible
NumberOfTickets.Add(TextArray(2))
PurchaseMethod.Add(TextArray(3))
End If
Next
End Sub
You can call this version of your code declaring the 4 lists
Dim TicketID = New List(Of String)()
Dim CustomerID = New List(Of String)()
Dim PurchaseMethod = New List(Of Char)()
Dim NumberOfTickets = New List(Of Integer)()
ReadInformation(TicketID, CustomerID, PurchaseMethod, NumberOfTickets, FileName)
Another approach more Object Oriented is to create a class that represent a line of your data. Inside the loop you create instances of that class and add the instance to a single List
Public Class CustomerData
Public Property TicketID As String
Public Property CustomerID As String
Public Property NumberOfTickets As Integer
Public Property PurchaseMethod As Char
End Class
Now the loop becomes
Private Function ReadInformation(FileName As String) as List(Of CustomerData)
Dim custData = New List(Of CustomerData)()
For Each line in File.ReadLines(FileName)
Dim TextArray = Line.Split(","c)
if TextArray.Length > 3 Then
Dim data = new CustomerData()
data.CustomerID = TextArray(0)
data.TicketID = TextArray(1)
data.NumberOfTickets = TextArray(2)
data.PurchaseMethod = TextArray(3)
custData.Add(data)
End If
Next
return custData
End Function
This version requires the declaration of just one list
You can call this version of your code passing just the filename and receiving the result fo the function
Dim customers = ReadInformation(FileName)
For Each cust in customers
Console.WriteLine(cust.CustomerID)
...
Next
Or use it as an array
Dim theFirstCustomer = customers[0]
Console.WriteLine(theFirstCustomer.CustomerID)

Related

Contents of List(Of String) are not saved

I am attempting to parse paragraphs such as the following...
Group 1. Does this or does that. Or Sometimes this. Or that.
Group 2. I do lots of things. But not this. Or that.
Group 3. I do this. I do that. Sometimes this. Sometimes that.
The "Group 1-3" are the org Names, and each following sentence separated by a period is a function.
Code:
Public Sub parseParagraphs(paragraphList As List(Of String))
Dim listOfOrgs As New List(Of EAB_Org)
Dim listOfFuntions As New List(Of String)
Dim orgName As String
For Each item In paragraphList
listOfFuntions.Clear()
Dim words As String() = item.Split(New Char() {"."c}) 'Splits on periods
orgName = words(0) 'Sets the orgName
For index As Integer = 1 To words.Count - 1 'rest of items in list are functions performed
listOfFuntions.Add(words(index))
Next
Dim anOrg As New EAB_Org(orgName, listOfFuntions)
listOfOrgs.Add(anOrg)
Next
End Sub
EAB Class:
Public Class EAB_Org
Dim orgName As String
Dim listOfTasks As List(Of String)
Public Sub New(theOrgName As String, theListOfTasks As List(Of String))
orgName = theOrgName
listOfTasks = theListOfTasks
End Sub
Public Function getOrgName()
Return orgName
End Function
Public Function getListOfTasks()
Return listOfTasks
End Function
End Class
For some reason, when I print out the contents of listOfOrgs, all the org names are correct, but the functions are all of the same and always the last set of functions read in.
Code I use to print:
Public Sub writeExcel(listOfOrgs As List(Of EAB_Org))
For Each anItem In listOfOrgs
Console.WriteLine(anItem.getOrgName)
For Each anotherItem In anItem.getListOfTasks
Console.WriteLine(anotherItem)
Next
Next
End Sub
Output Looks Like:
Group 1
I do this. I do that. Sometimes this. Sometimes that.
Group 2
I do this. I do that. Sometimes this. Sometimes that.
Group 3
I do this. I do that. Sometimes this. Sometimes that.
The problem is that in the constructor for EAB_Org, theListOfTasks is just a pointer to listOfFuntions (which you keep modifying) in the parseParagraphs Sub. In the constructor, you will need to create a new List(Of String) and copy the values from theListOfTasks into it.
Change the constructor to the following:
Public Sub New(theOrgName As String, theListOfTasks As List(Of String))
orgName = theOrgName
listOfTasks = New List(Of String)
For Each item As String In theListOfTasks
listOfTasks.Add(item)
Next
End Sub

Searching Multiple strings with 1st criteria, then searching those returned values with a different criteria and so on

so..
I have a txt file with hundreds of sentences or strings.
I also have 4 comboboxes with options that a user can select from and
each combobox is part of a different selection criteria. They may or may not use all the comboboxes.
When a user selects an option from any combobox I use a For..Next statement to run through the txt file and pick out all the strings that contain or match whatever the user selected. It then displays those strings for the user to see, so that if they wanted to they could further narrow down the search from that point by using the 3 remaining comboboxes making it easier to find what they want.
I can achieve this by using lots of IF statements within the for loop but is that the only way?
No, there are other ways. You can leverage LINQ to get rid of some of those if statements:
Private _lstLinesInFile As List(Of String) = New List(Of String)
Private Function AddClause(ByVal qryTarget As IEnumerable(Of String), ByVal strToken As String) As IEnumerable(Of String)
If Not String.IsNullOrWhiteSpace(strToken) Then
qryTarget = qryTarget.Where(Function(ByVal strLine As String) strLine.Contains(strToken))
End If
Return qryTarget
End Function
Public Sub YourEventHandler()
'Start Mock
Dim strComboBox1Value As String = "Test"
Dim strComboBox2Value As String = "Stack"
Dim strComboBox3Value As String = String.Empty
Dim strComboBox4Value As String = Nothing
'End Mock
If _lstLinesInFile.Count = 0 Then
'Only load from the file once.
_lstLinesInFile = IO.File.ReadAllLines("C:\Temp\Test.txt").ToList()
End If
Dim qryTarget As IEnumerable(Of String) = (From strTarget In _lstLinesInFile)
'Assumes you don't have to match tokens that are split by line breaks.
qryTarget = AddClause(qryTarget, strComboBox1Value)
qryTarget = AddClause(qryTarget, strComboBox2Value)
qryTarget = AddClause(qryTarget, strComboBox3Value)
qryTarget = AddClause(qryTarget, strComboBox4Value)
Dim lstResults As List(Of String) = qryTarget.ToList()
End Sub
Keep in mind this is case sensitive so you may want to throw in some .ToLower() calls in there:
qryTarget = qryTarget.Where(Function(ByVal strLine As String) strLine.ToLower().Contains(strToken.ToLower()))
I think a compound If statement is the simplest:
Dim strLines() As String = IO.File.ReadAllText(strFilename).Split(vbCrLf)
Dim strSearchTerm1 As String = "Foo"
Dim strSearchTerm2 As String = "Bar"
Dim strSearchTerm3 As String = "Two"
Dim strSearchTerm4 As String = ""
Dim lstOutput As New List(Of String)
For Each s As String In strLines
If s.Contains(strSearchTerm1) AndAlso
s.Contains(strSearchTerm2) AndAlso
s.Contains(strSearchTerm3) AndAlso
s.Contains(strSearchTerm4) Then
lstOutput.Add(s)
End If
Next

Length of 2D String list does not return the right value

I have a problem when I use .count in my 2D String list. This is the code:
If File.Exists(fullPath) = True Then
Dim readText() As String = File.ReadAllLines(fullPath)
Dim s As String
accountCounter = 0
For Each s In readText
accountList.Add(New List(Of String))
accountList.Add(New List(Of String))
accountList.Add(New List(Of String))
accountList(accountCounter).Add(s.Split(",")(0))
accountList(accountCounter).Add(s.Split(",")(1))
accountList(accountCounter).Add(s.Split(",")(2))
accountCounter += 1
Next
print_logs(accountList.count)
End If
The result is this:
{{name,email,password},{name2,email2,password2},{name3,email3,password3},{name4,email4,password4}}
beacuse in the file there are the following lines:
name,email,password
name2,email2,password2
name3,email3,password3
name4,email4,password4
But data is not the problem, the real problem is the Count method, it returns (12). I think that it returns 4 * 3 result, because if I add this in the code:
print_logs(accountList(0).Count)
it correctly returns 3.
So, how can I just return 4?
In this code you create three new rows everytime you do an iteration... If there are four lines in your text files then you will create twelve...
Do this instead :
If File.Exists(fullPath) = True Then
Dim readText() As String = File.ReadAllLines(fullPath)
Dim s As String
accountCounter = 0
For Each s In readText
accountList.Add(New List(Of String))
accountList(accountCounter).Add(s.Split(",")(0))
accountList(accountCounter).Add(s.Split(",")(1))
accountList(accountCounter).Add(s.Split(",")(2))
accountCounter += 1
Next
print_logs(accountList.count)
End If
And if you want to make it even better :
If File.Exists(fullPath) = True Then
Dim readText() As String = File.ReadAllLines(fullPath)
For Each s As String In readText
Dim newList = New List(Of String)
newList.Add(s.Split(",")(0))
newList.Add(s.Split(",")(1))
newList.Add(s.Split(",")(2))
accountList.Add(newList)
Next
print_logs(accountList.count)
End If

Splitting file into parts for dictionary use

I have an uploaded file, displaying
Han 33.3
Han 5.66
Han 8.3
Chewbacca 99.4
Chewbacca 100.3
Chewbacca 98.1
I need to make an average for each han and Chewbacca using a dictionary, but first I have to split the list in order to do that. How do I split them for this purpose.
I'm making the assumption that the whitespace between the name and quantity is a single space. I'm also calling your values "scores" and Han and Chewbacca "players" for my example solution. The result splits the line into individual key-value pairs; each key represents the list of values found; it:
Imports System.IO
Dim pathToYourFile As String = "Path to your file with file name"
Dim f As StreamReader = File.OpenText(pathToYourFile)
Dim fileText As String = f.ReadToEnd
f.Close()
Dim singleSpace As String = " " 'single space between quotes
Dim playerScores As New SortedDictionary(Of String, List(Of Double))
Dim lines() As String = fileText.Split(vbCrLf.ToCharArray())
For i As Integer = 0 To lines.Length - 1
Dim scoreLine() As String = lines(i).Split(" ".ToCharArray())
Dim playerName As String = scoreLine(0)
Dim score As Double = Double.Parse(scoreLine(1))
If playerScores.ContainsKey(playerName) Then
playerScores(playerName).Add(score)
Else
Dim list As New List(Of Double)
list.Add(score)
playerScores.Add(playerName, list)
End If
Next i
Try this:
Public Class DataClass
Public Property Name() As String
Public Property Value() As Decimal
End Class
' ...
Public Shared Function GetAverageDict(lines As IEnumerable(Of String)) _
As Dictionary(Of String, Decimal)
Dim lst As New List(Of DataClass)()
For Each line As String In lines
Dim lastSpaceIndex = line.LastIndexOf(" ")
If (lastSpaceIndex >= 0) Then
Dim name = line.Substring(0, lastSpaceIndex).Trim()
Dim value = Decimal.Parse(line.Substring(lastSpaceIndex + 1), _
System.Globalization.CultureInfo.InvariantCulture)
lst.Add(New DataClass() With { .Name = name, .Value = value })
End If
Next
Dim averages = From g In From x In lst _
Group x By key = x.Name _
Select New With { .Name = key, _
.Average = Group.Average(Function(y) y.Value) }
Return averages.ToDictionary(Function(x) x.Name, Function(y) y.Average)
End Function
The function first gets the parts from each line. It assumes that the last space is the separator between the parts. This way, the name can also contain space characters.
The data is collected in a list that is afterwards grouped by the name. By calling ToDictionary the result of the grouping operation is converted in a dictionary.
Call the function like this:
Dim dict = GetAverageDict(System.IO.File.GetLines(filePath))

List(of String) or Array or ArrayList

Hopefully a simple question to most programmers with some experience.
What is the datatype that lets me do this?
Dim lstOfStrings as *IDK*
Dim String0 As String = "some value"
Dim String1 As String = "some value"
Dim String2 As String = "some value"
Dim String3 As String = "some value"
Dim String4 As String = "some value"
Dim String5 As String = "some value"
lstOfStrings.add(String0, String1, String2, String3)
I would access these like this
Dim s1 = lstOfStrings(0)
Dim s2 = lstOfStrings(1)
Dim s3 = lstOfStrings(2)
Dim s4 = lstOfStrings(3)
if I use List(of String)
I am only able to .add one thing to the list (at a time), and in my function I want to be able to store several values(at a time).
Solution:
Private Function Foo() As List(Of String)
Dim temp1 As String
Dim temp2 As String
Dim temp3 As String
Dim temp4 As String
Dim temp5 As String
Dim temp6 As String
Dim inputs() As String = {temp1, temp2, temp3, temp4, temp5, temp6}
Dim lstWriteBits As List(Of String) = New List(Of String)(inputs)
Return lstWriteBits
End Function
List(Of String) will handle that, mostly - though you need to either use AddRange to add a collection of items, or Add to add one at a time:
lstOfString.Add(String1)
lstOfString.Add(String2)
lstOfString.Add(String3)
lstOfString.Add(String4)
If you're adding known values, as you show, a good option is to use something like:
Dim inputs() As String = { "some value", _
"some value2", _
"some value3", _
"some value4" }
Dim lstOfString as List(Of String) = new List(Of String)(inputs)
' ...
Dim s3 = lstOfStrings(3)
This will still allow you to add items later as desired, but also get your initial values in quickly.
Edit:
In your code, you need to fix the declaration. Change:
Dim lstWriteBits() As List(Of String)
To:
Dim lstWriteBits As List(Of String)
Currently, you're declaring an Array of List(Of String) objects.
You can do something like this,
Dim lstOfStrings As New List(Of String) From {"Value1", "Value2", "Value3"}
Collection Initializers
Neither collection will let you add items that way.
You can make an extension to make for examle List(Of String) have an Add method that can do that:
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension()>
Public Sub Add(ByVal list As List(Of String), ParamArray values As String())
For Each s As String In values
list.Add(s)
Next
End Sub
End Module
Now you can add multiple value in one call:
Dim lstOfStrings as New List(Of String)
lstOfStrings.Add(String1, String2, String3, String4)
look to the List AddRange method here
Sometimes I don't want to add items to a list when I instantiate it.
Instantiate a blank list
Dim blankList As List(Of String) = New List(Of String)
Add to the list
blankList.Add("Dis be part of me list") 'blankList is no longer blank, but you get the drift
Loop through the list
For Each item in blankList
' write code here, for example:
Console.WriteLine(item)
Next
You can use IList(Of String) in the function :
Private Function getWriteBits() As IList(Of String)
Dim temp1 As String
Dim temp2 As Boolean
Dim temp3 As Boolean
'Pallet Destination Unique
Dim temp4 As Boolean
Dim temp5 As Boolean
Dim temp6 As Boolean
Dim lstWriteBits As Ilist = {temp1, temp2, temp3, temp4, temp5, temp6}
Return lstWriteBits
End Function
use
list1.AddRange(list2) to add lists
Hope it helps.
For those who are stuck maintaining old .net, here is one that works in .net framework 2.x:
Dim lstOfStrings As New List(of String)( new String(){"v1","v2","v3"} )