Why won't the else statement run? - vb.net

I am writing a function that checks to see if all elements in an array are equal, but for some reason, the else statement never seems to run, even when the if condition IS NOT TRUE. Any reason for this weird behavior? I actually displayed the result of the boolean expression a(i) = a(i + 1) and it was false. What could be going on here?
VB.NET Code:
Function EqualItems(ByVal a As Integer())
For i As Integer = 1 To a.Length - 1
If a(i) = a(i + 1) Then
If i + 1 = a.Length Then
Return True
End If
Else
Return False
End If
Next
End Function

There are more than a few things wrong here, I will explain in a bit...
First here's what I would do using Linq. Just make sure to Import System.Linq at the top of your class file...
Public Function IsEqual(ByVal a As Integer()) As Boolean
Return a IsNot Nothing AndAlso a.count > 0 AndAlso a.Distinct.Count() = 1
End Function
Breakdown of function
Make sure the array is not nothing.
We have more than one item so we can compare the other's in the array.
Finally do the compare of the items. The .Distinct.Count() = 1 will return a boolean of either True or False compare to all items that are in the array...
Note: Not good for comparing some objects this way...
Your Issue's
The first problem is this: For i As Integer = 1 To a.Length - 1. Should start at 0 for arrays. So it should look like this: For i As Integer = 0 To a.Length - 1.
The next is: If a(i) = a(i + 1) Then. This is where you would throw the IndexOutOfRange exception as because there might be not index at: a(i + 1). Solution: If Not (i + 1 = a.Length) Then check before trying to access that index...
You can declare a Boolean variable to False before everything. Then if anywhere the items are not equal return false or set the boolean to false and return that...
On a side note
Implement some Try Catch blocks to catch and handle the errors. Turn Option Strict On... If you had this on it would say something about the function may not return anything (cant remember what exactly that message is off-hand).

Related

Sorting List(Of T) stopping early

I have a custom class called SaveFile. One property it has is SaveNumber and I'm trying to sort the list by that property. I read a bunch of articles here and got it to sort properly but it's stopping early? The case in which I noticed this is with set that has 79 saves. It would sort: 1, 2, 3, 4, 5, 6, 7, 10, 11, ... 30, 8, 31, ... 70, 9, 71, .. The code I use is
saveList.Sort(Function(x, y) x.CompareTo(y))
But if I use the code:
For i = 0 To 3
saveList.Sort(Function(x, y) x.CompareTo(y))
Next
then it sorts right but it takes a very long time and one set has over 700 SaveFiles in it so it takes almost 5 minutes for my program to load. Any ideas?
This is the code that I have for my CompareTo function:
Public Function CompareTo(y As SaveFile) As Integer Implements IComparable(Of SaveFile).CompareTo
'If neither are an autosave then compare save number
If Not Me.Text.StartsWith("autosave") And Not y.Text.StartsWith("autosave") Then
If Me.SaveNumber.ToString.Length > y.SaveNumber.ToString.Length Then
Return False
ElseIf Me.SaveNumber.ToString.Length < y.SaveNumber.ToString.Length Then
Return True
End If
Return Me.SaveNumber < y.SaveNumber
'if either is an autosave
Else
'Create to comparable integers with
'a value of 4. We set the value to
'4 because it is higher than the 3
'available autosaves, making it sort
'after any autosaves if only one is
'an autosave.
Dim xComp As Integer = 4
Dim yComp As Integer = 4
'If x is an autosave then figure out
'which autosave number it is.
If Me.Text.StartsWith("autosave") Then
Select Case True
Case Me.Text.EndsWith("1")
xComp = 1
Case Me.Text.EndsWith("2")
xComp = 2
Case Me.Text.EndsWith("3")
xComp = 3
End Select
End If
'if y is an autosave then figure out
'which autosave number it Is.
If y.Text.StartsWith("autosave") Then
Select Case True
Case y.Text.EndsWith("1")
yComp = 1
Case y.Text.EndsWith("2")
yComp = 2
Case y.Text.EndsWith("3")
yComp = 3
End Select
End If
Return xComp < yComp
End If
End Function
First, asking 2 questions in one post is not a good idea because it reduces the chances someone will know the answer to both. For example, without seeing the code that loads these things or even what they are, makes it just a guess why it takes so long to load.
For the sorting, your CompareTo method is flawed. From MSDN:
Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object.
That is, it should return -1 (precedes), 1 (follows) or 0 (same). Yours just returns Boolean:
If Me.SaveNumber.ToString.Length > y.SaveNumber.ToString.Length Then
Return False
ElseIf Me.SaveNumber.ToString.Length < y.SaveNumber.ToString.Length Then
Return True
End If
...
Return xComp < yComp
We have no idea what type SaveNumber is, but if it is am integer, comparing the length of the string form if it is not the same as comparing the value:
' Me vs Other
Return "9".Length < "7".Length
That will return False (0) when it by value, it should return 1. Turning on Option Strict would have flagged the incorrect return type, which might have led you to the answer. It should be something like this, ignoring the "auto" logic:
Public Function CompareTo(other As SaveItem) As Integer _
Implements IComparable(Of SaveItem).CompareTo
... special handling for "auto"
If Me.SaveNumber = other.SaveNumber Then
Return 0
ElseIf Me.SaveNumber < other.SaveNumber Then
Return -1
Else
Return 1
End If
End Function
But, you may not even need that (assuming again that SaveNumber is an int):
saveItems = saveItems.OrderBy(Function(q) q.SaveNumber).ToList()
IComparable.CompareTo() might be needed in order to handle the "autosave" logic but it might be able to be handled in the OrderBy() depending on the information the class exposes.

Longest Common substring breaking issue

Hi I have a function that finds the longest common substring between two strings. It works great except it seems to break when it reaches any single quote mark: '
This causes it to not truly find the longest substring sometimes.
Could anyone help me adjust this function so it includes single quotes in the substring? I know it needs to be escaped someplace I'm just not sure where.
Example:
String 1: Hi there this is jeff's dog.
String 2: Hi there this is jeff's dog.
After running the function the longest common substring would be:
Hi there this is jeff
Edit: seems to also happen with "-" as well.
It will not count anything after the single quote as part of the substring.
Here's is the function:
Public Shared Function LongestCommonSubstring(str1 As String, str2 As String, ByRef subStr As String)
Try
subStr = String.Empty
If String.IsNullOrEmpty(str1) OrElse String.IsNullOrEmpty(str2) Then
Return 0
End If
Dim num As Integer(,) = New Integer(str1.Length - 1, str2.Length - 1) {}
Dim maxlen As Integer = 0
Dim lastSubsBegin As Integer = 0
Dim subStrBuilder As New StringBuilder()
For i As Integer = 0 To str1.Length - 1
For j As Integer = 0 To str2.Length - 1
If str1(i) <> str2(j) Then
num(i, j) = 0
Else
If (i = 0) OrElse (j = 0) Then
num(i, j) = 1
Else
num(i, j) = 1 + num(i - 1, j - 1)
End If
If num(i, j) > maxlen Then
maxlen = num(i, j)
Dim thisSubsBegin As Integer = i - num(i, j) + 1
If lastSubsBegin = thisSubsBegin Then
subStrBuilder.Append(str1(i))
Else
lastSubsBegin = thisSubsBegin
subStrBuilder.Length = 0
subStrBuilder.Append(str1.Substring(lastSubsBegin, (i + 1) - lastSubsBegin))
End If
End If
End If
Next
Next
subStr = subStrBuilder.ToString()
Return subStr
Catch e As Exception
Return ""
End Try
End Function
I tried it with dotnetfiddle and there it is working with your Code you posted. Please activate your warnings in your project. You have function with no return value and you return an integer or a string. This is not correct. How are you calling your function?
Here is my example I tested for you:
https://dotnetfiddle.net/mVBDQp
Your code works perfectly like Regex! As far as I can see, there is really nothing wrong with your code.
Here I even tested it under more severe case:
Public Sub Main()
Dim a As String = ""
Dim str1 As String = "Hi there this is jeff''s dog.-do you recognize this?? This__)=+ is m((a-#-&&*-ry$##! <>Hi:;? the[]{}re this|\ is jeff''s dog." 'Try to trick the logic!
Dim str2 As String = "Hi there this is jeff''s dog. ^^^^This__)=+ is m((a-#-&&*-ry$##! <>Hi:;? the[]{}re this|\ is jeff''s dog."
LongestCommonSubstring(str1, str2, a)
Console.WriteLine(a)
Console.ReadKey()
End Sub
Note that I put '-$#^_)=+&|\{}[]?!;:.<> all there. Plus I tried to trick your code by giving early result.
But the result is excellent!
You could probably put more actual samples on the inputs which give you problems. Else, you could possibly describe the environment that you use/deploy your code into. Maybe the problem lies elsewhere and not in the code.
The quickest way to solve this would be to use an escape code and replace all the ' with whatever escape code you use

Return the previous index in vb.net?

I have a For Each loop that is looping through an array of strings to find the first string with a length of three characters. For example, when looping through the array, if the first 3 character string is the 4th index of the array, I would like for it to return the 3rd (previous) index of the array. Any help would be appreciated.
For Each piece As String In p
If piece.Length = 3 Then
'Return previous index
End If
Next
You have a couple of options.
If p is a collection accessible by index (ie: IList(Of T)), you can switch to a For loop, and return the element at the current index -1.
Otherwise, you can keep the previous item in a separate variable, and return it when your condition is met.
Dim lastItem as String
For Each piece As String In p
If piece.Length = 3 Then
Return lastItem ' Will return Nothing if this is the first item...
End If
lastItem = piece ' Store this for next time
Next
How about something like this:
For i As Integer = 1 To p.Count - 1
If p(i).Length = 3 Then
'Return previous index
Return p(i - 1)
End If
Next
Note the loop will have to start at 1 (not zero) otherwise you could return the (0-1)th element of the array which won't exist
I would use .FindIndex, if you have a List(Of T):
Dim i As Integer = p.FindIndex(Function(x) x.Length = 3)
If i > 0 Then
Dim previous As String = p(i - 1)
'Do something
End If
If you have a String(), you can also use the Array version:
Array.FindIndex(Of String)(p, Function(x) x.Length = 3)

VBA: Don't go into loop when array is empty

I have a loop that can look like this:
For Each article In artAll
Next
or like this:
For i = 0 To Ubound(artAll)
Next
When the array length is 0, I get an error message. What is a good way to skip the loop when the array is empty? I suspect that I should use
On Error Goto
but I need help finalizing a solution.
If Len(Join(artAll, "")) = 0 Then
'your for loops here
Should work
I use this function to test for empty arrays:
Public Function isArrayEmpty(parArray As Variant) As Boolean
'Returns false if not an array or dynamic array that has not been initialised (ReDim) or has been erased (Erase)
If IsArray(parArray) = False Then isArrayEmpty = True
On Error Resume Next
If UBound(parArray) < LBound(parArray) Then isArrayEmpty = True: Exit Function Else: isArrayEmpty = False
End Function
Then in your main code:
If isArrayEmpty(yourArray) Then
'do something - typically:
MsgBox "Empty Array"
Exit Function
End If
For i = LBound(yourArray,1) To UBound(yourArray,1)
'do something
Next i
I like the solution given by #Dan but thought I would throw out there how I would normally handle an undimensionalized array:
Dim lngUboundTest As Long
lngUboundTest = -1
On Error Resume Next
lngUboundTest = UBound(artAll)
On Error GoTo 0
If lngUboundTest >= 0 Then
'Your loop...
This is an old question, but I found this solution to the problem, and it could be helpful to others:
If (Not myArray) = True Then
'Undimensionalized array. Respond as needed.
Else
'Array isn't empty, you can run your loop.
End If
It helped my out in a recent project, and found it to be very handy.
I found this thread looking for a solution to a problem where looping through a multidimensional array would fail if a dimensioned element was empty. I created the array by looping through a source that could have up to 6 datasets. Then after processing I would repeat this 19 more times.
Dim varDeskData As Variant
Dim varDesk As Variant
ReDim varDesk(1 To 6)
For y = 1 To 6
ReDim varDeskData(1 To 4)
varDeskData(1) = "nifty integer from source(y)"
varDeskData(2) = "nifty string from source(y)"
varDeskData(3) = "another nifty string from source(y)"
varDeskData(4) = "another nifty string from source(y)"
varDesk(y) = varDeskData
Next y
When I ran the following, I would get the first three processed but then it would fail on the fourth, because I had only loaded three into the parent array:
For y = 1 To 6
If varDesk(y)(1) > 0 Then
... do nifty stuff ...
End If
End If
Using the IsEmpty procedure on the top level elements of the parent array fixed this:
For y = 1 To 6
If IsEmpty(varDesk(y)) = False Then
If varDesk(y)(1) > 0 Then
... do nifty stuff ...
End If
End If
End If

Parallel.For VS For. Why there is this difference?

I have an array (i), and I want to do some math calculations based on the i value with a Parallel.For().
But the problem is, after running the Parallel.For(), the values on my array are still 0.
This happens when my for is from 0 to 0.
This is my code :
Dim a(10) As Double
Parallel.For(0, 0, Sub(i)
a(i) = i + 2
'There is some calculations based on instead of previous line!
'But anyway, the result will be on a(i).
End Sub)
MessageBox.Show(a(0)) 'This returns 0!
For i As Integer = 0 To 0
a(i) = i + 2
Next
MessageBox.Show(a(0)) 'But this returns 2!
What is the problem?
From Microsoft's documentation
If fromInclusive is greater than or equal to toExclusive, then the method returns immediately without performing any iterations.
Therefore nothing will happen when you use Parallel.For(0,0,etc).
Try Parallel.For(0,1) and see if you get a result.
Your correct code should look like this
Dim a(10) As Double
Parallel.For(0, 1, Sub(i)
a(i) = i + 2
'There is some calculations based on instead of previous line!
'But anyway, the result will be on a(i).
End Sub)
MessageBox.Show(a(0)) '2!
For i As Integer = 0 To 0
a(i) = i + 2
Next
MessageBox.Show(a(0)) '2