If statement not catching catching condition - vb.net

I'm looping through a list of decimals and I use an if statement to catch any junk data and not chart it if any appears in the list, though the if statement doesn't seem to be catching this and the junk data gets charted anyways. I've tried Continue For and exiting the sub altogether, but it rarely seems to be caught. My code below:
For i = 1 To 8
If hotTemps(i - 1) > 3000 Or hotTemps(i - 1) < -400 Then
Continue For
End If
If celsius.Checked And sysTime.Checked Then
Chart1.Series(i - 1).Points.AddXY(TimeOfDay.ToString("HH:mm:ss"), CDec(hotTemps(i - 1)))
ElseIf fahrenheit.Checked And sysTime.Checked Then
Chart1.Series(i - 1).Points.AddXY(TimeOfDay.ToString("HH:mm:ss"), CDec((hotTemps(i - 1))) * 1.8 + 32)
ElseIf celsius.Checked And elapsedTime.Checked Then
Chart1.Series(i - 1).Points.AddXY(elapsed, CDec(hotTemps(i - 1)))
ElseIf fahrenheit.Checked And elapsedTime.Checked Then
Chart1.Series(i - 1).Points.AddXY(elapsed, CDec((hotTemps(i - 1))) * 1.8 + 32)
End If
Next

Simplify your loop to check your logic.
Dim lst As New List(Of Integer)
For a = 0 To 7
If a > 6 Or a < 3 Then
Continue For
End If
lst.Add(a)
Next
For Each i In lst
Debug.Print(i.ToString)
Next
This produces
3
4
5
6
Is this the expected result?

Related

VBA dice roll with addition

VBA dice roll is very easy thing even for me, but I need specific type, when rolling 6 means you can roll again and add the two rolls together (plus when you roll 6 twice in a row, you get third roll and so on).
I have tried two approaches, but both failed
Sub roll_dice_1()
Dim result As Range
Set result = Range("A1")
result = Application.WorksheetFunction.RandBetween(1, 6)
If result = 6 Then
result = result + Application.WorksheetFunction.RandBetween(1, 6)
Do Until Application.WorksheetFunction.RandBetween(1, 6) <> 6
result = result + Application.WorksheetFunction.RandBetween(1, 6)
Loop
Else
End If
End Sub
This one however can produce result of 12, which is clearly impossible, because twice 6 should give third roll
Sub roll_dice_2()
Dim result As Range
Set result = Range("A1")
result = Application.WorksheetFunction.RandBetween(1, 6)
If result = 6 Then
Do Until Application.WorksheetFunction.RandBetween(1, 6) <> 6
result = result + Application.WorksheetFunction.RandBetween(1, 6)
Loop
Else
End If
End Sub
This one works even worse, because it can return 6.
I tried search high and low, but all that I got were simple codes for simple throws, rolls with two dices and rolls when certain results can be rerolled. Again all options pretty easy, unlike this one
Your issue is you're generating a random number to test against and then generating a different one to add to your result. They need to be the same. Also VBA has it's own random function.
Sub roll_dice()
Dim result As Integer, roll as Integer
Dim lowerbound As Integer, upperbound As Integer
lowerbound = 1
upperbound = 6
result = Int((upperbound - lowerbound + 1) * Rnd + lowerbound)
If result = upperbound Then
roll = result
Do While roll = upperbound
roll = Int((upperbound - lowerbound + 1) * Rnd + lowerbound)
result = result + roll
Loop
End If
MsgBox result
End Sub
The loop is wrong. You cannot roll in the condition and then roll again to accumulate as these are already 2 rolls.
Basically what you need is a loop where the condition comes last, e.g.
Result = 0
Do
Roll =...
Result = result + roll
Loop while roll <> 6
Seems the issue if the handling of 6, if it is to thow reroll, then you should implement:
...
roll = 6
do while roll = 6
roll = Int(( 6 * Rnd + 1)
ShowRoll(roll)
loop
DoStuffWithRollValue
...
this will show every roll until row is 1-5
ShowRoll is the call to the animation or other method of showing the roll
Sub roll_dice()
Dim die1, die2 As Integer
'Randomize
die1 = (Hour(Rnd) Mod 6) + 1
die2 = (Hour(Rnd) Mod 6) + 1
Exit Sub

I have 8 rows but when (i = 7) it says (i + 1) is out of range?

I have a DataGridView with 8 Rows. In the following Sub i have an If statement to only do something when i is less than the RowCount, this is purposely so when i use (i + 1) on the last row it will still be in range, yet it is not? I can't figure out why. Would appreciate any help.
This is the sub
Public Sub Durations(dgv As DataGridView)
For i As Integer = 0 To dgv.RowCount
Dim intTotalMinutesOfRows As Integer
Dim IntHoursForRows As Integer
Dim intMinutesForRows As Integer
If i < dgv.RowCount Then
If dgv.Rows(i).Cells("EmployeeID").Value = dgv.Rows(i + 1).Cells("EmployeeID").Value _
And dgv.Rows(i).Cells("Date").Value = dgv.Rows(i + 1).Cells("Date").Value Then
intTotalMinutesOfRows = intTotalMinutesOfRows + dgv.Rows(i).Cells("TotalDurationOfRow").Value
Else
intTotalMinutesOfRows = intTotalMinutesOfRows + dgv.Rows(i).Cells("TotalDurationOfRow").Value
IntHoursForRows = Math.Floor(intTotalMinutesOfRows / 60)
intMinutesForRows = intTotalMinutesOfRows Mod 60
dgv.Rows(i).Cells("TotalDurationForDay").Value = "" & IntHoursForRows & " Hrs " & intMinutesForRows & " Mins"
intTotalMinutesOfRows = 0
End If
End If
Next
Iterate to RowCount - 1 only:
For i As Integer = 0 To dgv.RowCount - 1
^^^
Note that despite you've got If i < dgv.RowCount Then, later in this conditional operator you're trying to access Rows(i + 1), which causes the exception for i = dgv.RowCount - 1. So you have to change your condition to If i < dgv.RowCount - 1 Then as well.
Indexes are zero-based (they start at 0), so index 7 is the 8th row.
Row : 1 2 3 4 5 6 7 8
Index : 0 1 2 3 4 5 6 7
Infact even your loop's end is wrong, because i will go to whatever RowCount is. Thus if RowCount is 8 then i will be 8 as well in the end (which doesn't work, as seen in the indexes above).
In order to loop to the last index you must loop to RowCount - 1:
For i As Integer = 0 To dgv.RowCount - 1

For Loop running error

This code doesn't find the correct output
for say n= 1 (although it gives the correct output for say n= 2,3,4..etc.)
if we put n= 1 to find x then the i loop will continue from 1 to 0, hence the first term in x should vanish and leftover should be the second term 5; but it gives 0 ?
Is there any limitation on the input n to run the for loop ?I would appreciate any help.
Function math(n As Integer) As Double
Dim i As Integer
Dim x As Double
For i = 1 To n - 1
x = (n - 1) * 2 + 5
sum = sum + x
Next i
math = sum
End Function
Why not simply:
Function math(n As Integer) As Double
Math = ((n - 1) * 2 + 5) * Abs((n - 1) - (n = 1))
End Function
???
if the answer is correct then Math = (n * 2 + 3) * Abs((n - 1) - (n = 1)) would be easier to understand and make much more sense
In the for loop, if you don't precise the Step, the variable will only increment by 1.
And here, you start at 1 to go to 0, so the loop won't execute, you need to test n to cover both cases :
Function math(n As Integer) As Double
If n < 0 Then Exit Function
Dim i As Integer
Dim x As Double
Dim Summ As Double
Select Case n
Case Is > 1
For i = 1 To n - 1
x = (i - 1) * 2 + 5
Summ = Summ + x
Next i
Case Is = 1
Summ = (n - 1) * 2 + 5
Case Is = 0
Summ = 5
Case Else
MsgBox "This case is not supported", vbInformation + vbOKOnly
Exit Function
End Select
math = Summ
End Function
If n = 1, you end up with For i = 1 To 0 which is incorrect and
should be expressed For i = 1 To 0 STEP -1.
So I suggest you add the STEP BYand make sure it is either 1 to -1 depending on N.

Working with Excel ranges and arrays

In VBA, I can easily pull in an sheet\range into an array, manipulate, then pass back to the sheet\range. I'm having trouble doing this in VB.Net though.
Here's my code.
Rng = .Range("a4", .Cells(.UsedRange.Rows.Count, .UsedRange.Columns.Count))
Dim SheetArray(,) As Object = DirectCast(Rng.Value(Excel.XlRangeValueDataType.xlRangeValueDefault), Object(,))
For X As Integer = 0 To SheetArray.GetUpperBound(0)
If IsNothing(SheetArray(X, 0)) Then Exit For
SheetArray(X, 6) = SheetArray(X, 3)
SheetArray(X, 7) = CDbl(SheetArray(X, 3).ToString) - CDbl(SheetArray(X, 1).ToString) - _
CDbl(SheetArray(X, 7).ToString)
For Y As Integer = 0 To 3
SheetArray(X, Y * 2 + 1) = Math.Round(CDbl(SheetArray(X, Y * 2 + 1).ToString), 3)
Next
If Math.Abs(CDbl(SheetArray(X, 7).ToString)) > 0.1 Then _
.Range(.Cells(X + 1, 1), .Cells(X + 1, 8)).Font.Color = -16776961
Next
I'm getting an error on the first If IsNothing(SheetArray(X, 0)) Then Exit For
line. It is telling me index is out of bounds of the array. Any idea why? The SheetArray object contains the data, but I just am not sure how to get to it.
In the For you have to loop from 0 to Count - 1:
For X As Integer = 0 To SheetArray.GetUpperBound(0) - 1
'...
Next
That will fix your problem.

How can I make this VB.NET code more efficient and faster?

I've been trying to make this code faster and more efficient for a few days now, but it still doesn't seem as efficient as it could be.
Sub Main()
Dim watch As Stopwatch = Stopwatch.StartNew()
Dim l As New List(Of ULong)(CType(My.Application.CommandLineArgs.Item(0), ULong))
For i As ULong = 1 To l.Capacity
' ONE LINE IF STMT: If l.Capacity And 1 <> 0 Then If i And 1 = 0 Then l.Add((i * i) - 1) Else l.Add((i * i) + 1) Else If i And 1 = 0 Then l.Add((i * i) + 1) Else l.Add((i * i) - 1)
If l.Capacity And 1 <> 0 Then
If i And 1 = 0 Then
l.Add((i * i) - 1)
Else
l.Add((i * i) + 1)
End If
Else
If i And 1 = 0 Then
l.Add((i * i) + 1)
Else
l.Add((i * i) - 1)
End If
End If
Next i
Console.WriteLine(String.Join(","c, l.ToArray))
watch.Stop()
Console.WriteLine(watch.Elapsed.TotalMilliseconds)
Console.ReadLine()
End Sub
It currently runs 100 iterations of i in 4.3 milliseconds.
I feel like the nested if statements are the main bottleneck here, but I'm not sure of any way I can change them.
So, can this code be made more efficient?
Thanks... :)
First off, pull the If l.Capacity And 1 <> 0 out of the loop, since it’s always going to be the same.
Then, drop the bit operations in favour of more readable i Mod 2 = 0 tests: you seem to think that this is more efficient, but in reality such trivial optimisations are best left to the compiler and runtime, they have no place in your code and I seriously doubt that they have any measurable impact.
If this is still to inefficient, don’t use an initial capacity and Add. Instead, use Resize and indexed access to the elements. Then you can also get rid of the other If statements by using two loops: one for the even elements and one for the odd elements.
That said, the Join operation is probably by far the slowest step here (apart from the actual printing to the console, maybe) and there’s nothing you can do to optimise that.
Finally, I find the CType horribly unreadable: what you’re doing here isn’t a cast – it’s a parsing operation. Why not write it as one? ULong.Parse(…). Also, why are you using the unwieldy My.Application.CommandLineArgs.Item instead of accepting the command line arguments as a parameter to Main?
Once I only correct your errors, as I think you intended, I get this output when using Ctrl+F5 with Visual Studio 2010 with a Release build:
0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117,2208,2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040,5185,5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217,9408,9605,9800,10001
33.9106
That's with this code:
Sub Main()
Dim watch As Stopwatch = Stopwatch.StartNew()
Dim l As New List(Of ULong)(CInt(My.Application.CommandLineArgs(0)))
For i As ULong = 1 To CULng(l.Capacity)
' ONE LINE IF STMT: If l.Capacity And 1 <> 0 Then If i And 1 = 0 Then l.Add((i * i) - 1) Else l.Add((i * i) + 1) Else If i And 1 = 0 Then l.Add((i * i) + 1) Else l.Add((i * i) - 1)
If (l.Capacity And 1) <> 0 Then
If (i And 1UL) = 0UL Then
l.Add((i * i) - 1UL)
Else
l.Add((i * i) + 1UL)
End If
Else
If (i And 1UL) = 0UL Then
l.Add((i * i) + 1UL)
Else
l.Add((i * i) - 1UL)
End If
End If
Next i
Console.WriteLine(String.Join(","c, l.ToArray))
watch.Stop()
Console.WriteLine(watch.Elapsed.TotalMilliseconds)
Console.ReadLine()
End Sub
Using LINQ:
0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117,2208,2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040,5185,5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217,9408,9605,9800,10001
13.0721
That's with:
Sub Main()
Dim watch As Stopwatch = Stopwatch.StartNew()
Dim arg = CInt(My.Application.CommandLineArgs(0))
Console.WriteLine(String.Join(","c, Enumerable.Range(1, arg).Select(
Function(i) ((i * i +
If((arg And 1) <> 0,
If((i And 1) = 0, -1, 1),
If((i And 1) = 0, 1, -1))).ToString()))))
watch.Stop()
Console.WriteLine(watch.Elapsed.TotalMilliseconds)
Console.ReadLine()
End Sub
Now optimised:
0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117,2208,2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040,5185,5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217,9408,9605,9800,10001
12.5956
And at this point I thought I clearly hit the Console.WriteLine variance being within the timing, but even with the code below I still get 12 to 15 milliseconds...
Sub Main()
Dim watch As Stopwatch = Stopwatch.StartNew()
Dim arg = CInt(My.Application.CommandLineArgs(0))
Dim fn As Func(Of Integer, String) = If((arg And 1) <> 0,
Function(i As Integer) ((i * i + If((i And 1) = 0, -1, 1)).ToString()),
Function(i As Integer) ((i * i + If((i And 1) = 0, 1, -1)).ToString()))
Dim s = String.Join(","c, Enumerable.Range(1, arg).Select(fn))
watch.Stop()
Console.WriteLine(s)
Console.WriteLine(watch.Elapsed.TotalMilliseconds)
Console.ReadLine()
End Sub