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