Creating a string from an array of strings. Fastest method? - vba

I have an array of strings (A through E) that I want to join into one string ("A B C D E"). Should I loop through the array or use the Join function?
Dim MyArray(5) as String
Dim MyString as String
MyArray(1) = "A"
MyArray(2) = "B"
MyArray(3) = "C"
MyArray(4) = "D"
MyArray(5) = "E"
Which is faster and more advisable?
This?
MyString = MyArray(1)
For i = 2 To 5
MyString = MyString & " " & MyArray(i)
Next
Or this?
MyString = Join(MyArray, " ")

For a 100k array
Sub test()
Dim aArr(1 To 100000) As String
Dim i As Long
Dim sString As String
Dim snTimer As Single
FillArray aArr
snTimer = Timer
For i = 1 To 100000
sString = sString & Space(1) & aArr(i)
Next i
Debug.Print Timer - snTimer
snTimer = Timer
sString = Join(aArr, Space(1))
Debug.Print Timer - snTimer
End Sub
Join is the clear winner
2.050781
0
the reason is that every time you concatenate with & memory has to be reallocated to accommodate the new array (which is all strings are anyway). With Join, you're just copying one array (the source array) to another array (the string) and VBA already knows the size.

If you want to combine many strings efficiently you can define a stringbuilder class.
Running the code below to build up a string of numbers up to a million takes just a fraction of a second (0.3s). Building an array and using Join takes not far off the same time (0.25s), the call to the Join function takes only about 10% of that time.
If the strings are already in an array then it makes sense to use Join but with a small number of strings the difference is unlikely to be noticeable anyway.
Sub JoinStringTest()
Dim i As Long, t As Double
Dim sb As New StringBuilder
Dim sbRet As String
Dim joinRet As String
t = Timer
For i = 1 To 1000000
sb.Append CStr(i)
Next
sbRet = sb.Text
Debug.Print "SB", Timer - t
t = Timer
Dim a(1000000) As String
For i = 1 To 1000000
a(i) = CStr(i)
Next i
joinRet = Join(a, "")
Debug.Print "Join", Timer - t
Debug.Print sbRet = joinRet
End Sub

Related

Delete first letter of the words using visual basic

I have a code, which can change last letters of words to the dot. I need to how, how to change the code, so when I write some words, in output I will get them without first letter?
for ex:
Input: Hello,how are you?
Output: ello, ow re ou?
Here is my code:
Sub New5
dim s, ns as String
dim r as String
s = inputbox("Input text")
r = "Inputed text:" & chr(9) & s & chr(13)
for i = 2 to len(s)
if mid(s,i,1)=" " then ns = ns + "." else ns = ns + mid(s,i-1,1)
next i
ns = ns + "."
r = r & "Result of work:" & chr(9) & ns
MsgBox r
End Sub
For VB6:
Private Sub Convert()
Dim strIn as string
Dim strA() As String
Dim strOut As String
Dim iX As Integer
strIn - "Hello, how are you?"
strA = Split(strIn, " ")
For iX = 0 To UBound(strA)
strA(iX) = Mid$(strA(iX), 2)
Next
strOut = Join(strA, " ")
End Sub
Incidentally your libreoffice tag is also inappropriate as LibreOffice doesn't use the same language as vb6 or vba.
Sorry, just saw this was tagged vb6. This is a vb.net answer.
If you want to get rid of the first letter of each word, the first thing to do is get the words. String.Split will return an array based on the split character you provide. In this case that character is a space. The small c following the string tells the compiler that this is Char.
Now we can loop through each word and cut off the first letter. I am storing the shortened words in a List(Of String). You can get rid of the first letter by using Substring passing the start index. We want to start at the second letter so we pass 1. Indexes start at 0 for the first letter.
Finally, use String.Join to put everything back together.
Chr, Len, Mid, and MsgBox are all left overs from VB6. They work for backward compatibility but it is a good idea to learn the .net classes functionality.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
New5()
End Sub
Private Sub New5()
Dim input = InputBox("Input text")
Dim words = input.Split(" "c)
Dim ShortWords As New List(Of String)
For Each word In words
ShortWords.Add(word.Substring(1))
Next
Dim shortenedString = String.Join(" ", ShortWords)
MessageBox.Show(shortenedString)
End Sub

manipulate StringBuilder in vb.net

I have a Note as stringBuilder with word and date: reval 41/50/50
I want to manipulate it, so I will have: reval 05/05/14.
(The date is only when I have the word reval before)
My function is:
Sub correctDateShowing(ByRef Note As StringBuilder)
Dim index, i, j As Integer
For index = 0 To Note.Length - 2
If (Note(index).ToString = "r" And Note(index + 1).ToString = "e") Then
For i = 6 To Note.Length - 1 'start from 6,because I want only the date to be reversed
'Here I am Stuck!!
Next
End If
Next
End Sub
I try to do some replacing with a tmp variable but it didn't work.
I will be glad to get some help.
Thanks All!!!
Sub CorrectDateShowing(ByRef Note As StringBuilder)
Dim str As String = Note.ToString()
Dim arr As String() = str.Split(" "c)
arr(1) = StrReverse(arr(1))
Note = New StringBuilder(arr(0) & " " & arr(1))
End Sub
Split the text into two parts, reverse the second part (the date) and then reconnect them.
Try this:
Dim tempCharArray As char[]
Dim dateStartIndex, dateLength As int
'' Here you need to calculate the date start index and date length (i guess the date length is always 8)
Note.CopyTo(dateStartIndex, tempCharArray, 0, dateLength)
Note.Replace(new String(tempCharArray), new String(Array.Reverse(tempCharArray)), dateStartIndex, dateLength)

Displaying the sum of a range of numbers?

I have to create a program that calculates the sum of a range of numbers entered by the user and displays in a label an expression with the numbers in range. So if I entered "10" as a starting number and "20" as an ending number, there would be a label that displays "10+11+12+13+14+15+16+17+18+19+20".
This is what I have so far. I'm not sure how to get the range of numbers and display it in a label. I'm also really new to Visual Basic (I'm taking it as a course in high school) so please dumb down your answer as much as possible :) Any help is appreciated! Thanks.
Dim intStartingNumber As Integer = Val(Me.txtStartNumber.Text)
Dim intEndingNumber As Integer = Val(Me.txtEndNumber.Text)
Dim intSum As Integer = 0
Me.lblNumbers.Text = intStartingNumber & "+" & intEndingNumber
For intStartingNumber = Val(Me.txtStartNumber.Text) To intEndingNumber Step 1
intSum = intSum + intStartingNumber
Next
Me.lblNumbersSum.Text = intSum
If you just want the total:
Dim StartNumber As Integer = Integer.Parse(txtStartNumber.Text)
Dim EndNumber As Integer = Integer.Parse(txtEndNumber.Text)
lblNumbersSum.Text = Enumerable.Range(StartNumber, EndNumber - StartNumber ).Sum()
If you really want the full text expressions:
Dim StartNumber As Integer = Integer.Parse(txtStartNumber.Text)
Dim EndNumber As Integer = Integer.Parse(txtEndNumber.Text)
Dim delimiter As String = ""
Dim expression As New StringBuilder()
For Each number As String IN Enumerable.Range(StartNumber, EndNumber - StartNumber )
expression.Append(delimiter).Append(number)
delimiter = "+"
Next number
lblNumbersSum.Text = expression.ToString()
This should work, albeit I haven't been able to test:
Dim intStartingNumber As Integer = Val(Me.txtStartNumber.Text)
Dim intEndingNumber As Integer = Val(Me.txtEndNumber.Text)
Dim intSum As Integer = 0
Dim intIndex As Integer
Dim strExpr As String
strExpr = Me.txtStartNumber.Text
'Setting up a new variable called intIndex so that intStartingNumber can stay static
For intIndex = Val(Me.txtStartNumber.Text) To intEndingNumber Step 1
intSum = intSum + intIndex
if intIndex > intStartingNumber Then
strExpr = strExpr & "+" & intIndex
End If
Next
Me.lblNumbersSum.Text = intSum
Me.lblNumbers.Text = strExpr
The idea is that you create a new variable called strExpr to hold the expression and then concatenate using & within the For loop. That way, as you add on the values arithmetically, you're also adding to the string that shows the calculation being done. I'm hoping that's what you were after.
If you get any errors, please comment below and I'll amend the script and explain.
As you are doing this to learn the basics of Basic (hah hah, never heard that one before), I will keep it simple:
' convert the input text into numbers
Dim startNumber As Integer = Integer.Parse(txtStartNumber.Text)
Dim endNumber As Integer = Integer.Parse(txtEndNumber.Text)
'TODO: optional - check that endNumber > startNumber
' we are going to put the sum and the text of the summation into
' variables; we might as well start them off with the first values
Dim sum As Integer = startNumber
Dim sumText As String = startNumber.ToString()
' now we just need to use a loop that goes from the second value to the end
For i As Integer = startNumber + 1 To endNumber
' we need to use the value i twice, once as a number...
sum = sum + i
' ... and once as a String
sumText = sumText & "+" & i.ToString()
Next
' show the results to the user
lblNumbersSum.Text = sum.ToString()
lblNumbers.Text = sumText
The default Step value for a For..Next loop is 1, so we don't need to specify that.
Instead of writing sum = sum + i, we could write sum += i, and similarly for sumText = sumText & "+" & i.ToString() we could write sumText &= "+" & i.ToString(). They are just ways of saving a bit of typing.
As Jens mentioned, it is usually better to use something called a StringBuilder to build a string in a loop, but I expect you will learn about that later. If you want to learn about it now, you could look at the Remarks section of the StringBuilder documentation.

Speed up large string data parser function

I currently have a file with 1 million characters.. the file is 1 MB in size. I am trying to parse data with this old function that still works but very slow.
start0end
start1end
start2end
start3end
start4end
start5end
start6end
the code, takes about 5 painful minutes to process the whole data.
any pointers and suggestions are appreciated.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sFinal = ""
Dim strData = textbox.Text
Dim strFirst = "start"
Dim strSec = "end"
Dim strID As String, Pos1 As Long, Pos2 As Long, strCur As String = ""
Do While InStr(strData, strFirst) > 0
Pos1 = InStr(strData, strFirst)
strID = Mid(strData, Pos1 + Len(strFirst))
Pos2 = InStr(strID, strSec)
If Pos2 > 0 Then
strID = Microsoft.VisualBasic.Left(strID, Pos2 - 1)
End If
If strID <> strCur Then
strCur = strID
sFinal += strID & ","
End If
strData = Mid(strData, Pos1 + Len(strFirst) + 3 + Len(strID))
Loop
End Sub
The reason that is so slow is because you keep destroying and recreating a 1 MB string over and over. Strings are immutable, so strData = Mid(strData... creates a new string and copies the remaining of the 1 MB string data to a new strData variable over and over and over. Interestingly, even VB6 allowed for a progressive index.
I would have processed the disk file LINE BY LINE and plucked out the info as it was read (see streamreader.ReadLine) to avoid working with a 1MB string. Pretty much the same method could be used there.
' 1 MB textbox data (!?)
Dim sData As String = TextBox1.Text
' start/stop - probably fake
Dim sStart As String = "start"
Dim sStop As String = "end"
' result
Dim sbResult As New StringBuilder
' progressive index
Dim nNDX As Integer = 0
' shortcut at least as far as typing and readability
Dim MagicNumber As Integer = sStart.Length
' NEXT index of start/stop after nNDX
Dim i As Integer = 0
Dim j As Integer = 0
' loop as long as string remains
Do While (nNDX < sData.Length) AndAlso (i >= 0)
i = sData.IndexOf(sStart, nNDX) ' start index
j = sData.IndexOf(sStop, i) ' stop index
' Extract and append bracketed substring
sbResult.Append(sData.Substring(i + MagicNumber, j - (i + MagicNumber)))
' add a cute comma
sbResult.Append(",")
nNDX = j ' where we start next time
i = sData.IndexOf(sStart, nNDX)
Loop
' remove last comma
sbResult.Remove(sbResult.ToString.Length - 1, 1)
' show my work
Console.WriteLine(sbResult.ToString)
EDIT: Small mod for the ad hoc test data

How to get an array to display all its values at once

Here is some sample code:
Dim arrValue(3) as Integer
arrValue(0) = 5
arrValue(1) = 4
arrValue(2) = 7
arrValue(3) = 1
How can I display those four values next to each other.
More specifically, given those values how can I make txtValue.Text = 5471
Edit:
The idea I had would be to use some sort of function to append each one to the end using a loop like this:
Dim finalValue
For i As Integer = 3 To 0 Step -1
arrValue(i).appendTo.finalValue
Next
Obviously that code wouldn't work though the premise is sound I don't know the syntax for appending things and I'm sure I wouldn't be able to append an Integer anyway, I would need to convert each individual value to a string first.
Another method is to use String.Join:
Sub Main
Dim arrValue(3) as Integer
arrValue(0) = 5
arrValue(1) = 4
arrValue(2) = 7
arrValue(3) = 1
Dim result As String = String.Join("", arrValue)
Console.WriteLine(result)
End Sub
If I understand your question correctly, you can use StringBuilder to append the values together.
Dim finalValue as StringBuilder
finalValue = new StringBuilder()
For i As Integer = 3 To 0 Step -1
finalValue.Append(arrValue(i))
Next
Then just return the finalValue.ToString()
Convert the integers to strings, and concatenate them:
Dim result as String = ""
For Each value as Integer in arrValue
result += value.ToString()
Next
Note: using += to concatenate strings performs badly if you have many strings. Then you should use a StringBuilder instead:
Dim builder as New StringBuilder()
For Each value as Integer in arrValue
builder.Append(value)
Next
Dim result as String = builder.ToString()
for i = lbound(arrValue) to ubound(arrValue)
ss=ss & arrValue(i)
next i
end for
debug.print ss
Dim value as string = ""
For A As Integer = 1 To Begin.nOfMarks
value += "Mark " & A & ": " & (Begin.Marks(A)) & vbCrLf
Next A