How to most efficiently replace this code to vb.net version? - vb.net

Public Function fileToColHarvest(ByRef stream As Scripting.TextStream, Optional ByRef limit As Integer = 2000000, Optional ByRef unique As Boolean = False, Optional ByRef FirstSectionAsKey As Boolean = False, Optional ByRef prob As Double = 1) As Generic.List(Of String)
Dim buffer As String
Dim i As Integer
If prob < 1 Then
End If
fileToColHarvest = New Generic.List(Of String)
Do While (Not (stream.AtEndOfStream))
i = i + 1
System.Windows.Forms.Application.DoEvents()
'If Microsoft.VisualBasic.Rnd < 0.01 Then
' appendToTextFile CStr(fileToColHarvest.Count) + "|" + microsoft.visualbasic.str(i) + "|" + buffer, RESULT, ForWriting
'End If
buffer = stream.ReadLine
'buffer = Microsoft.VisualBasic.Replace(buffer, " ", "+")
If Microsoft.VisualBasic.Rnd() < prob Then
If unique Then
If Not FirstSectionAsKey Then
fileToColHarvest.AddIfNotExist(buffer)
Else
fileToColHarvest.AddIfNotExist(buffer)
End If
Else
fileToColHarvest.Add(buffer)
End If
End If
If fileToColHarvest.Count() >= limit Then
Exit Do
End If
Loop
End Function
Basically I want to get rid Scripting.TextStream.
Also I want to read the text line by line

You can use StreamReader and asynchronous ReadLineAsync method.
Asynchronous approach will replace "ugly" Application.DoEvents()
Public Async Function FileToColHarvest(
pathToFile As String,
limit As Integer,
isUnique As Boolean,
isFirstSectionAsKey As Boolean,
prob As Single) As Task(Of List(Of String))
Dim lines = New List(Of String)()
Dim uniqueLines = New HashSet(Of String)()
Using stream As New FileStream(pathToFile, FileMode.Open)
Using reader As New StreamReader(stream)
While reader.EndOfStream = False
'Await will prevent blocking UI thread
var line = Await reader.ReadLineAsync()
If prob < VBMath.Rnd() Then Continue While
' I have removed check of isFirstSectionAsKey
' because based on your code it does same thing
If isUnique Then
uniqueLines.Add(line)
If uniqueLines.Count >= limit Then Return uniqueLines.ToList()
Else
lines.Add(line)
If lines.Count >= limit Then Return lines
End If
End While
End Using
End Using
Return If(isUnique, uniqueLines.ToList(), lines)
End Function
Not related but isUnique argument divide this method in two different logic - so I suggest instead of parameter introduce two different methods
FileToColHarvest(...)
FileToColHarvestWithUniqueOnly(...)

Related

Split() doesn't work properly

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)

Lempel-Ziv-Welch algorithm

Heys guys,
I'm trying to implement the Lempel-Ziv-Welch algorithm on byte level in VB.NET. Here is what the Code looks like so far:
Dim FileBytes As Byte() = {Convert.ToByte(12), Convert.ToByte(13), Convert.ToByte(12), Convert.ToByte(13), Convert.ToByte(12), Convert.ToByte(13)}
Dim bw As New BitWriter(New BinaryWriter(New FileStream(output, FileMode.Create)))
Dim ByteDictionary As New Dictionary(Of Byte(), Integer)
Dim DictionaryN As Integer = 1
Dim DictionaryMax As Integer = 4048
Dim outputs As New List(Of Integer)
Dim bts As New List(Of Byte)
For index As Integer = 0 To FileBytes.Length - 1
Dim currentbyte As Byte = FileBytes(index)
If ContainsByte(ByteDictionary, AddToList(bts, currentbyte).ToArray) Then
bts.Add(currentbyte)
Else
If bts.Count > 1 Then
ByteDictionary.Add(bts.ToArray, 255 + DictionaryN)
DictionaryN += 1
Else
ByteDictionary.Add(New Byte() {currentbyte}, currentbyte)
End If
Console.WriteLine(GetByteValue(ByteDictionary, bts.ToArray))
bts.Clear()
bts.Add(currentbyte)
End If
Next
End Sub
Public Function ContainsByte(ByVal dic As Dictionary(Of Byte(), Integer), ByVal bt As Byte()) As Boolean
Dim flag = True
For Each kp As KeyValuePair(Of Byte(), Integer) In dic
If ByteArrayEquals(kp.Key, bt) Then
Return True
End If
Next
Return False
End Function
Public Function AddToList(ByVal list As List(Of Byte), ByVal bt As Byte) As List(Of Byte)
Dim newlist = New List(Of Byte)(list)
newlist.Add(bt)
Return newlist
End Function
Public Function ByteArrayEquals(ByVal first As Byte(), ByVal second As Byte()) As Boolean
If first.Length = second.Length Then
Dim flag = True
For index As Integer = 0 To first.Length - 1
If first(index) <> second(index) Then
flag = False
End If
Next
Return flag
Else
Return False
End If
End Function
Public Function GetByteValue(ByVal dic As Dictionary(Of Byte(), Integer), ByVal bt As Byte()) As Integer
For Each kp As KeyValuePair(Of Byte(), Integer) In dic
If ByteArrayEquals(kp.Key, bt) Then
Return kp.Value
End If
Next
End Function
The idea behind my implementation is from https://www.cs.cf.ac.uk/Dave/Multimedia/node214.html . But somehow it doesn't work, it simply puts out the input bytes. What is wrong with it?
The main problem is these two lines:
If bts.Count > 1 Then
ByteDictionary.Add(bts.ToArray, 255 + DictionaryN)
In both lines here you're using bts where you should be using bts + currentByte, i.e. you want something like
Dim currentbyte As Byte = FileBytes(index)
Dim btsPlusCurrentByte As List(Of Byte) = AddToList(bts, currentbyte)
If ContainsByte(ByteDictionary, btsPlusCurrentByte.ToArray) Then
bts.Add(currentbyte)
Else
If btsPlusCurrentByte.Count > 1 Then
ByteDictionary.Add(btsPlusCurrentByte.ToArray, 255 + DictionaryN)
The other problem is that you'll complete the loop with data left in bts that you haven't output, so I think you'll need a block to do that afterwards. It may be safe to just do
Console.WriteLine(GetByteValue(ByteDictionary, bts.ToArray))
again after the Next but I haven't thought about that very carefully.
I also think you should be able to use .NET's own built-ins rather than your four helper functions.

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

write data into specific position in text file

I need to write in an existing text file at 30th position. I am using seek but not working. using below code. Using Startposition as 30.
Public Sub WriteToFile(ByVal data As DataTable, ByVal FileName As String, ByVal FieldLength As String, ByVal StartPosition As String)
Dim sbColumnData As New StringBuilder
Using writer = New StreamWriter(Directory.GetCurrentDirectory() + "\test.txt")
For Each oRecord In data.Rows
sbColumnData.Clear()
If oRecord(0).ToString().Length < FieldLength Then
sbColumnData.Append(oRecord(0).ToString().PadRight(FieldLength))
ElseIf oRecord(0).ToString().Length = FieldLength Then
sbColumnData.Append(oRecord.ToString())
Else
sbColumnData.Append(oRecord.ToString().Substring(0, FieldLength))
End If
writer.Seek(0, StartPosition )
writer.WriteLine(sbColumnData)
writer.Flush()
Next
End Using
End Sub
Your syntax is wrong. Try:
writer.Seek(StartPosition, SeekOrigin.Begin)
writer.Write(sbColumnData, 0, sbColumnData.Length);
https://msdn.microsoft.com/en-us/library/system.io.filestream.seek%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

VB.NET - Randomize() with a function call in a string.replace method

I have a chat system and i want to put a "random string generator".
In my chat i have to write "%random%" and it is replaces with a random string.
I have a problem though, if i type "%random%%random%%random%" for example, it will generate the same string 3 times.
• Here is my function:
Public Function getRandomString(ByVal len As Integer) As String
Randomize()
Dim stringMap as string = "abcdefghijklmnopqrstuwvxyz0123456789"
Dim rndString As String = ""
Dim rnd As New Random()
For i As Integer = 0 To len - 1
Randomize()
rndString &= stringMap.Substring(rnd.Next(0, stringMap.Length), 1)
Next
Return rndString
End Function
• And here is my function call:
Dim msg As String = "Random string: %random%%random%%random%"
msg = msg.Replace("%random%", getRandomString(8))
MsgBox(msg)
The output for example: Random string: 5z15if725z15if725z15if72
I guess this is because it keeps the 1st return value in memory and pastes it, how can i fix that ?
Do i have to make a string.replace function myself ? Thanks
Oh no! You shouldn't call Randomize() here at all! Random is used in combination with the Rnd() function of VB. Creating a new Random object is enough here.
The reason you are getting the same results every time is because you are creating a new Random every time. You should reuse the same object to get different results.
'Create the object once
Private Shared rnd As New Random()
Public Function getRandomString(ByVal len As Integer) As String
Dim stringMap as string = "abcdefghijklmnopqrstuwvxyz0123456789"
Dim rndString As String = ""
For i As Integer = 0 To len - 1
rndString &= stringMap.Substring(rnd.Next(0, stringMap.Length), 1)
Next
Return rndString
End Function
EDIT: I realize that in addition to the above changes, you need to call the getRandomString function for every "%random%". String.Replace only calls the function once and pastes the result everywhere. With Regex, you could do something like this:
msg = new Regex("%random%").Replace(input, Function (match) getRandomString(8))
An easy way to do it is to find the first occurrence of "%random%", replace that, then repeat as necessary.
Written as a console application:
Option Infer On
Module Module1
Dim rand As New Random
Public Function getRandomString(ByVal len As Integer) As String
Dim stringMap As String = "abcdefghijklmnopqrstuwvxyz0123456789"
Dim rndString As String = ""
For i As Integer = 0 To len - 1
rndString &= stringMap.Substring(rand.Next(0, stringMap.Length), 1)
Next
Return rndString
End Function
Function ReplaceRandoms(s As String) As String
Dim stringToReplace = "%random%"
Dim r = s.IndexOf(stringToReplace)
While r >= 0
s = s.Remove(r, stringToReplace.Length).Insert(r, getRandomString(stringToReplace.Length))
r = s.IndexOf(stringToReplace)
End While
Return s
End Function
Sub Main()
Dim msg As String = "Random string: %random%%random%%random%"
msg = ReplaceRandoms(msg)
Console.WriteLine(msg)
Console.ReadLine()
End Sub
End Module