There's a glitch when adding numerals to a line CSV (VB.NET) - vb.net

All of the number 6's in column 6 (Item(5)) should be deleted, and the rest of the numbers should be increased by 1. However, when the process is completed, I check the file and the file is unchanged.
Dim liness As New List(Of String)(File.ReadAllLines("F:\Computing\Spelling Bee\stdnt&staffdtls.csv"))
For Each line As String In liness
Dim item() As String = line.Split(","c)
Do
If item(5) = 6 Then
liness.Remove(line)
Else : Exit Do
End If
Exit Do
Loop
Console.WriteLine("Have you already entered the next school years, year 3's? (y/n)")
Dim year3s As String = Console.ReadLine
If year3s = "Y" Or year3s = "y" Then
For i As Integer = 1 To liness.Count - 1 'this will read to the end of the array list once
If item(5) > 3 And item(5) < 6 Then
item(5) = item(5) + 1
End If
Next
ElseIf year3s = "N" Or year3s = "n" Then
For i As Integer = 1 To liness.Count - 1 'this will read to the end of the array list once
If item(5) > 2 And item(5) < 6 Then
item(5) = item(5) + 1
End If
Next
End If
File.WriteAllLines("F:\Computing\Spelling Bee\stdnt&staffdtls.csv", liness)
Exit For
Next
Exit Do
ElseIf enter.Key = ConsoleKey.End Then
Console.Clear()
adminmenu()
End If

You are updating the 'item' array, but not the 'liness' list. When you write the new 'liness' list to the file, any changes you made to the 'item' array are ignored.
Also, you are writing the 'liness' list back to the file for every loop iteration - this has to be wrong - you probably want to do that after the loop.

While I don't condone using the Split() function for parsing CSV data, I'll leave that part alone here in order to highlight other improvements in the code:
Dim minYear As Integer = 2
Console.WriteLine("Have you already entered the next school years, year 3's? (y/n)")
If Console.ReadLine().ToUpper().Trim() = "Y" Then minYear = 3
Dim NewLines = File.ReadLines("F:\Computing\Spelling Bee\stdnt&staffdtls.csv").
Select(Function(l) l.Split(","c) ).
Where(Function(l) Integer.Parse(l(5)) <> 6 ).
Select(Function(l)
Dim x As Integer = Integer.Parse(l(5))
If x >= minYear Then x += 1
l(5) = x.ToString()
Return String.Join(",", l)
End Function).ToList()
File.WriteAllLines("F:\Computing\Spelling Bee\stdnt&staffdtls.csv", NewLines)

Related

How can put split integers in a two-dimensional array?

I making matrix calculator. so, Textbox_A contains vbCrLf and tries to put it in Array_A.
and I would like to put Array_A in Result Matrix.
It's like
Textbox_a:
(1 2 3)
(4 5 6)
[Matrix to Array]
Array_a(0)(0) = 1
Array_a(0)(1) = 2
Array_a(0)(2) = 3
Array_a(1)(0) = 4
...
I have done string splits through several articles, but changing them to integers causes many problems.
This picture is Matrix_A and result Matrix
I don't know if the size of your initial matrix, formatted as text, is fixed, but here is some code to help you get started. The code tries to calculate the number of columns and rows.
The actual code is in the TextToArray function, that takes as input as string formatted as you described:
(1 2 3) (cr/lf)
(4 5 6)
and outputs a two dimensional array. The Main sub is just used to call TextToArray and display results.
So, in your example, you should pass TextBox_A.Text to TextToArray
There is minimal error checking here - you should add more to validate that data entered are numbers (check the Integer.TryParse function) and that the number of columns is the same across lines.
Sub Main(args As String())
Dim myInput As String = "(1 2 3)" & vbCrLf & "(4 5 6)"
Dim ret As Integer(,) = TextToArray(myInput)
If ret IsNot Nothing Then
For i As Integer = 0 To ret.GetUpperBound(0) - 1
For n As Integer = 0 To ret.GetUpperBound(1) - 1
Console.WriteLine(i & "," & n & "=" & ret(i, n))
Next
Next
Else
Console.WriteLine("No results - wrong input format")
End If
Console.ReadLine()
End Sub
Private Function TextToArray(matrix As String) As Integer(,)
Dim noOfRows As Integer = matrix.Split(vbCrLf).Count
Dim noOfColumns As Integer = 0
If noOfRows > 0 Then
noOfColumns = matrix.Split(vbCrLf)(0).Split(" ").Count
End If
If noOfColumns > 0 And noOfRows > 0 Then
Dim ret(noOfRows, noOfColumns) As Integer
Dim lines As String() = matrix.Split(vbCrLf)
Dim row As Integer = 0
For Each line As String In lines
Dim col As Integer = 0
line = line.Replace("(", "")
line = line.Replace(")", "")
For Each s As String In line.Split(" ")
ret(row, col) = Integer.Parse(s)
col += 1
Next
row += 1
Next
Return ret
Else
Return Nothing
End If
End Function
This outputs:
0,0=1
0,1=2
0,2=3
1,0=4
1,1=5
1,2=6

Index textboxes value (from two textboxes)

I have the two textboxes:
First:
Textbox1.lines(0) = 50
Textbox1.lines(1) = 65
Textbox1.lines(2) = 41
Textbox1.lines(3) = 27
Textbox1.lines(4) = 6
Textbox1.lines(5) = 6
Second:
Textbox2.lines(0) = 27
Textbox2.lines(1) = 41
Textbox2.lines(2) = 65
Textbox2.lines(3) = 6
Textbox2.lines(4) = 50
Textbox2.lines(5) = 6
in a third textbox I should display the index that contains the values ​​from the first textbox, but in the second.
Textbox3.lines(0) = 4 (50 of the first textbox is on the second line (lines4)
Textbox3.lines(1) = 2 (65 of the first textbox is on the second line (lines2)
Textbox3.lines(2) = 1 (41 of the first textbox is on the second line (lines1)
Textbox3.lines(3) = 0 (27 of the first textbox is on the second line (lines0)
Textbox3.lines(4) = 3 (6 of the first textbox is on the second line (lines4)
Textbox3.lines(5) = 5 (6 of the first textbox is on the second line (lines5)
although it already exists on line 4 (Number 6), we will move next line, because that line has already been considered. or both index can be displayed.
or somehow the line value becomes null (0) so that it is not taken.
Code: it doesn't work properly, unfortunately.
For Each line In TextBox1.Lines
For l As Integer = 1 To TextBox1.Lines.Length - 1
If TextBox2.Lines(l) = line Then
TextBox3.AppendText(l)
End If
Next
Next
This should work :
For Each line In TextBox1.Lines
Dim i As Integer = 0
While (i < TextBox1.Lines.Length)
If TextBox2.Lines(i) = line Then
TextBox3.AppendText(i & Environment.NewLine)
Continue For
End If
i += 1
End While
Next
With Continue For, the code go to the for's next loop.
Or if you want to display all iterations :
For Each line In TextBox1.Lines
Dim i As Integer = 0
While (i < TextBox1.Lines.Length)
If TextBox2.Lines(i) = line Then
TextBox3.AppendText(i & " ")
End If
i += 1
End While
TextBox3.AppendText(Environment.NewLine)
Next
This approach uses a Dictionary with the number as the key, and a Queue of indices as the value.
When we first encounter a number from TextBox1, we build a queue of all indices where the number occurs in TextBox2. Then each time we encounter that number, we dequeue the next available number where it occurred. If there are none left, then we return -1.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim results As New List(Of String)
Dim occurrences As New Dictionary(Of Integer, Queue(Of Integer))
For Each number As String In TextBox1.Lines
If Not occurrences.ContainsKey(number) Then
occurrences.Add(number, New Queue(Of Integer))
For i As Integer = 0 To TextBox2.Lines.Count - 1
If TextBox2.Lines(i) = number Then
occurrences(number).Enqueue(i)
End If
Next
End If
If occurrences(number).Count > 0 Then
results.Add(occurrences(number).Dequeue)
Else
results.Add("-1")
End If
Next
TextBox3.Lines = results.ToArray
End Sub
I managed to do that as well with the help of a list. In order to work, the number of lines must be equal.
Dim valI As New List(Of Integer)
For nIndex As Integer = 0 To Textbox2.Lines.Length -1
For i As Integer = 0 To TextBox1.Lines.Length - 1
If TextBox2.Lines(nIndex) = TextBox1.Lines(i) Then
If valI.Contains(i) Then
Else
valI.Add(i)
End If
End If
Next
Textbox3.AppendText(vbNewline & valI.Item(nIndex))
Next

Finding Sequence of numbers in Text file

Hello I'm having quite some trouble with this task that was given to me.
I need to find a Sequence of 8 consecutive numbers in a Text file and Put that Line into a MsgBox.
So far I've only found
For Each i As Char In fileLocation
If IsNumeric(i) Then
result += i
End If
Next`
MsgBox(result)
But that won't help me I guess
Edit:
an example Line woudl look like this:
! MK 90 GRAD ALU L 10793013 144 63.00 90 1 3745 !
In this case I would need the 10793013 as an output
Edit 2:
this is the code I currently managed to create
Dim objReader As New System.IO.StreamReader(fileLocation)
Do While objReader.Peek() <> -1
concounter = 0
zeileInhalt = objReader.ReadLine()
ListBox1.Items.Add(zeileInhalt)
For Each zeichen As Char In zeileInhalt
If IsNumeric(zeichen) Then
concounter += 1
vorhanden = True
If vorhanden = False Then
ListBox1.Items.Add(zeileInhalt)
End If
ElseIf IsNumeric(zeichen) = False And concounter = 8 Then
concounter = 0
ElseIf IsNumeric(zeichen) = False And concounter < 8 Then
concounter = 0
ListBox1.Items.Remove(zeileInhalt)
ElseIf concounter > 8 Then
concounter = 0
ListBox1.Items.Remove(zeileInhalt)
vorhanden = False
End If
Next
Loop
'For i As Integer = 0 To fileLocation.Length <> -1
objReader.Close()
The counter itself appears to work however for some reason no entries end up in my listbox.
am I missing a case where the entries are getting removed?
PS: I hope you don't mind the german variable names. If you do
zeileInhalt = content of the row
zeichen = character
vorhanden = existing
Here's another approach to try out:
Dim values() As String
Using objReader As New System.IO.StreamReader(fileLocation)
Do While Not objReader.EndOfStream
values = objReader.ReadLine().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
For Each value As String In values
value = value.Trim()
If value.Length = 8 AndAlso value.All(Function(c) Char.IsDigit(c)) Then
ListBox1.Items.Add(value)
Exit For
End If
Next
Loop
End Using
try to introduce a counter to check the consecutivity in your if clause and reset it and result string to zero once it's not numeric!
Dim result As String = ""
Dim conCounter As Integer = 0
For Each i As Char In fileLocation
If Char.IsDigit(i) Then
conCounter = (conCounter + 1)
result = (result + i)
Else
conCounter = 0
If (result.Length < 8) Then
result = ""
End If
End If
Next
MsgBox(result)
for each word in fileLocation
Dim noExp As New Regex("([0-9]{8,11})")
Dim m As Match = noExp.Match(word)
If Not m.Success Then Throw New Exception("No sequence number found")
Dim c = m.Groups(1).Captures(0)
Msgbox(c.value)
next
how about this ?

Retrieve exists consecutive lines value VB.Net

I should show if there is a consecutive value of lines, if the line contains consecutive values. when it contains at least 2, to display something, when it does not contain, to display something else.
Like my Textbox:
Textbox1.Text = 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
For x As Integer = 1 To 4
Next
if I have
2
4
4
10
22
can i somehow show if there are consecutive lines?
MsgBox("Exist")
Else
2
4
22
25
MsgBox("Not Exists")
TextBoxes have a `Lines property, which makes it easy to retrieve lines
'Get the lines from the textbox
Dim lines As String() = Textbox1.Lines
If lines.Length >= 2 Then
Dim consecutiveLines As Boolean = False
Dim previousLine As String = lines(0)
For i = 1 To lines.Length - 1
Dim currentLine = lines(i)
If currentLine = previousLine Then
consecutiveLines = True
Exit For
End If
previousLine = currentLine
Next
If consecutiveLines Then
'Display somthing
Else
'Display somthing else
End If
End If
The trick is to start looping at the second line (lines(1)) and to compare it with the previous line. We have to update the previous line at the end of each loop.
We also store the outcome in a Boolean variable consecutiveLines.
Alternatively, we could access two consecutive lines directly:
'Get the lines from the textbox
Dim lines As String() = Textbox1.Lines
If lines.Length >= 2 Then
Dim consecutiveLines As Boolean = False
For i = 1 To lines.Length - 1 'Start at second line
If lines(i) = lines(i - 1) Then
consecutiveLines = True
Exit For
End If
Next
If consecutiveLines Then
'Display somthing
Else
'Display somthing else
End If
End If
This leads to a somewhat shorter code.

Need Help to Reduce Processing Time for Large CSV Data

I've read through some of the previous questions on speed up processing of large CSV data. I've implement some of the ideas and i got some improvement on processing time. However i still need to further cut down the processing time hopefully someone can help me.
I think my code is too long, I'll try to simplify. Here is what my code suppose to do:
1. Read through a csv file.
2. Group the data by first column; calculate total sum of each column and return the result.Example (Raw Data): A B C1 2 31 2 32 4 42 4 4Result:A B C1 4 62 8 8Note: My actual data will be 100MB file with 630 columns and 29000 rows, total 18.27M records.
Here is how i achieve it:Method 1:
1. Read a csv file through Filestream.
2. Use Split to split the returned string and process line by line, field by field.
3. Storing the result in an array and save the result in a text file.
Note on Method1: Time to process the data using this method takes ~1 min 20 secs.Method 2:1. Read a csv file through Filestream.2. Feed the data into different threads before start process. (For now i feed 100 lines of data into different thread, fix 5 threads for now due to CPU resource constraint)3. Use Split to split the returned string and process line by line, field by field in each thread.4. Join all result from every threads and store in an array. Save the result in text file.Note on Method 2: Time to process the data using this method takes ~50 secs.So i got ~30secs improvement migrating from Method 1 to Method 2. I was wondering whether what i can do to further improve the process time. I've tried to cut down the data into smaller section like 100 lines x 100 columns and process it but the time to process the data become longer instead.Hopefully some one can help me on this.Thank you in advance.Edit:Here is my code for Method 2 (I'll skip Method 1 as i'm not using it already), I have a subroutine that manage the assignment of threads for every 100 lines read from filestream, execute each threads and return the result, finally update the all the results into single array before write the result into file. I tried to make the code as simple as possible. Hopefully this will give more idea to you all on how i process my data.'Subroutine that assign smaller section of raw data into different threadsSub process_control(byval filename as string) Dim sread As New FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read) Dim read As New StreamReader(sread) Dim t1 As System.Threading.Thread Dim value, data1(), data2(), data3(), data4(), data5(), threadid(), result1(0), result2(0), result3(0), result4(0), result5(0) As String Dim row as integer Dim rowlimit as integer = 99 Dim check1 as boolean = true row = 0 check = false ReDim data1(rowlimit), data2(rowlimit), data3(rowlimit), data4(rowlimit), data5(rowlimit), threadid(4) do
value = read.ReadLine
If row < rowlimit + 1 then
If data1(rowlimit) = "" Then
data1(row) = value
ElseIf data2(rowlimit) = "" Then
data2(row) = value
ElseIf data3(rowlimit) = "" Then
data3(row) = value
ElseIf data4(rowlimit) = "" Then
data4(row) = value
ElseIf data5(rowlimit) = "" Then
data5(row) = value
End If
Else
If data1(rowlimit) <> "" And data2(rowlimit) = "" And data3(rowlimit) = "" And data4(rowlimit) = "" And data5(rowlimit) = "" Then
threadid(0) = ""
t1 = New Threading.Thread(Sub()
result1 = process(data1).Clone
threadid(0) = System.Threading.Thread.CurrentThread.ManagedThreadId
End Sub)
t1.Start()
row = 0
data2(row) = value
ElseIf data1(rowlimit) <> "" And data2(rowlimit) <> "" And data3(rowlimit) = "" And data4(rowlimit) = "" And data5(rowlimit) = "" Then
threadid(1) = ""
t1 = New Threading.Thread(Sub()
result2 = process(data2).Clone
threadid(1) = System.Threading.Thread.CurrentThread.ManagedThreadId
End Sub)
t1.Start()
row = 0
data3(row) = value
ElseIf data1(rowlimit) <> "" And data2(rowlimit) <> "" And data3(rowlimit) <> "" And data4(rowlimit) = "" And data5(rowlimit) = "" Then
threadid(2) = ""
t1 = New Threading.Thread(Sub()
result3 = process(data3).Clone
threadid(2) = System.Threading.Thread.CurrentThread.ManagedThreadId
End Sub)
t1.Start()
row = 0
data4(row) = value
ElseIf data1(rowlimit) <> "" And data2(rowlimit) <> "" And data3(rowlimit) <> "" And data4(rowlimit) <> "" And data5(rowlimit) = "" Then
threadid(3) = ""
t1 = New Threading.Thread(Sub()
result4 = process(data4).Clone
threadid(3) = System.Threading.Thread.CurrentThread.ManagedThreadId
End Sub)
t1.Start()
row = 0
data5(row) = value
ElseIf data1(rowlimit) <> "" And data2(rowlimit) <> "" And data3(rowlimit) <> "" And data4(rowlimit) <> "" And data5(rowlimit) <> "" Then
threadid(4) = ""
t1 = New Threading.Thread(Sub()
result5 = process(data5).Clone
threadid(4) = System.Threading.Thread.CurrentThread.ManagedThreadId
End Sub)
t1.Start()
row = 0
check1 = True
End If
row += 1
End If If check1 = True Then
Do
System.Threading.Thread.Sleep(100)
Loop Until threadid(0) <> "" And threadid(1) <> "" And threadid(2) <> "" And threadid(3) <> "" And threadid(4) <> ""
row = 0
ReDim data1(rowlimit)
data1(row) = value
row += 1
result1_update(result1) ' consolidate result into a single array
result2_update(result2) ' consolidate result into a single array
result3_update(result3) ' consolidate result into a single array
result4_update(result4) ' consolidate result into a single array
result5_update(result5) ' consolidate result into a single array
check1 = False
ReDim data2(rowlimit), data3(rowlimit), data4(rowlimit), data5(rowlimit)
End If
loop until read.endofstreamend sub
' Function that calculate the sum of each row and columns Function process(ByVal data() As String) As String()
Dim line(), line1(), result() As String
Dim check As Boolean
redim result(0)
For n = 0 To (data.Count - 1)
if result(0) = "" and result.count = 1 then
result(result.count-1) = data(n)
else
check = true
line1 = Split(data(n), ",", -1, CompareMethod.Text)
For m = 0 to (result.count-1)
line = split(result(m),",",-1, CompareMethod.Text)
if line1(0) = line(0) then
check = false
for o = 1 to (line1.count-1)
line(o) = val(line1(o)) + val(line(o))
next o
result(m) = join(line,",")
exit for
end if
Next m
if check = true then
redim preserve result(result.count)
result(result.count-1) = join(line1,",")
end if
end if
Next n
redim preserve result(result.count-2)
process = result.clone
End Function
Looking at your code I noticed a couple of things:
you're using Val which is very easy to use but has a high overhead. Integer.Parse would work much more efficiently.
You're converting from string to number back to string way more than you should have to. Since your summary will only be a fraction of the size of your complete data, you shouldn't have any trouble storing the results in memory. A Dictionary(Of Integer, Integer()) would work well for this.
Consider this code which will read the data, summarize it and put the data in a format easy to write to a file all in less than 10 secs. using random integers up to 1000:
Function SummarizeData(filename As String, delimiter As Char) As Dictionary(Of Integer, Integer())
Dim limit As Integer = 0
SummarizeData = New Dictionary(Of Integer, Integer())
Using sr As New IO.StreamReader(filename)
'Since we don't need the first line for the summary we can read it get _
'the upper bound for the array, and discard the line.
If Not sr.EndOfStream Then
limit = sr.ReadLine.Split(delimiter).Length - 1
Else : Throw New Exception("Empty File")
End If
Do Until sr.EndOfStream
'This creates an array of integers representing the data in one line.
Dim line = sr.ReadLine.Split(" "c).Select(Function(x) Integer.Parse(x)).ToArray
'If the key is already in the dictionary we increment the values
If SummarizeData.ContainsKey(line(0)) Then
For I = 1 To limit
SummarizeData.Item(line(0))(I) += line(I)
Next
Else
'If not we create a new element using the line as the initial values
SummarizeData.Add(line(0), New Integer(limit) {})
SummarizeData.Item(line(0)) = line
End If
Loop
End Using
End Function
To use the function and write the data, this would work:
Dim results = SummarizeData("data.txt", ","c)
'If you don't need the results sorted you can gain a few fractions of a second by _
'removing the Order By clause
IO.File.WriteAllLines("results.txt", (From kvp In results
Order By kvp.Key
Select String.Join(",", kvp.Value)).ToArray)