VBScript Error Handling in For Each loops [duplicate] - loops

A colleague and I were trying to figure out a way of doing the equivalent of a "continue" statement within a VBScript "For/Next" loop.
Everywhere we looked we found people had no way to do this in VBScript without having nasty nestings, which is not an option for us since it is a quite big loop.
We came out with this idea. Would it work just as a "continue(to next iteration)"? Does anyone have any better workaround or improvement suggestion?
For i=1 to N
For workaroundloop = 1 to 1
[Code]
If Condition1 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[...]
Next
Next
Thanks for your comments

Your suggestion would work, but using a Do loop might be a little more readable.
This is actually an idiom in C - instead of using a goto, you can have a do { } while (0) loop with a break statement if you want to bail out of the construct early.
Dim i
For i = 0 To 10
Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False
Next
As crush suggests, it looks a little better if you remove the extra indentation level.
Dim i
For i = 0 To 10: Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False: Next

A solution I decided on involved the use of a boolean variable to track if the for loop should process its instructions or skip to the next iteration:
Dim continue
For Each item In collection
continue = True
If condition1 Then continue = False End If
If continue Then
'Do work
End If
Next
I found the nested loop solutions to be somewhat confusing readability wise. This method also has its own pitfalls since the loop doesn't immediately skip to the next iteration after encountering continue. It would be possible for a later condition to reverse the state of continue. It also has a secondary construct within the initial loop, and requires the declaration of an extra var.
Oh, VBScript...sigh.
Also, if you want to use the accepted answer, which isn't too bad readability wise, you could couple that with the use of : to merge the two loops into what appears to be one:
Dim i
For i = 0 To 10 : Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False : Next
I found it useful to eliminate the extra level of indentation.

One option would be to put all the code in the loop inside a Sub and then just return from that Sub when you want to "continue".
Not perfect, but I think it would be less confusing that the extra loop.

I use to use the Do, Loop a lot but I have started using a Sub or a Function that I could exit out of instead. It just seemed cleaner to me. If any variables you need are not global you will need to pass them to the Sub also.
For i=1 to N
DoWork i
Next
Sub DoWork(i)
[Code]
If Condition1 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[...]
End Sub

We can use a separate function for performing a continue statement work. suppose you have following problem:
for i=1 to 10
if(condition) then 'for loop body'
contionue
End If
Next
Here we will use a function call for for loop body:
for i=1 to 10
Call loopbody()
next
function loopbody()
if(condition) then 'for loop body'
Exit Function
End If
End Function
loop will continue for function exit statement....

I've always used an Do While loop. This works with both For type loops.
For iIndex = 0 to 100
Do
If bCondition then Exit Do
...
Loop While False
Next
IMHO, this just looks clean.
I just saw Crush's answer, at the bottom. Sorry for the duplicate answer.

Implement the iteration as a recursive function.
Function Iterate( i , N )
If i == N Then
Exit Function
End If
[Code]
If Condition1 Then
Call Iterate( i+1, N );
Exit Function
End If
[Code]
If Condition2 Then
Call Iterate( i+1, N );
Exit Function
End If
Call Iterate( i+1, N );
End Function
Start with a call to Iterate( 1, N )

Try use While/Wend and Do While / Loop statements...
i = 1
While i < N + 1
Do While true
[Code]
If Condition1 Then
Exit Do
End If
[MoreCode]
If Condition2 Then
Exit Do
End If
[...]
Exit Do
Loop
Wend

I think you are intended to contain ALL YOUR LOGIC under your if statement. Basically:
' PRINTS EVERYTHING EXCEPT 4
For i = 0 To 10
' you want to say
' If i = 4 CONTINUE but VBScript has no continue
If i <> 4 Then ' just invert the logic
WSH.Echo( i )
End If
Next
This can make the code a bit longer, but some people don't like break or continue anyway.

Related

Exiting Nested For loop VBA and re-looping

I'm trying to work with a nested For loop. I essentially have 2 arrays and I want to use the 1st variable in array1 with the 1st variable in array2 to do some operation, and so on until the array is exhausted. Unfortunately, the Exit For, doesn't exit for the For levels. So I've tried to use a goTo command, however then I get an error of "This array is fixed or temporarily locked" clearly because I'm trying to re-access the array. I'm stuck how to get around this in VBA. Below is my code where at MsgBox some operation (that will need the pairs (dAFL,AFL),(dSF,SF), etc) will take place:
For Each vN In Array(dAFLcell, dSFcell, dSOcell, dFIGcell, dIBAcell, dIBXcell)
a = 0
For Each vN2 In Array(AFLcell, SFcell, SOcell, FIGcell, IBAcell, IBXcell)
If i = a Then
MsgBox a
GoTo end_of_for
End If
a = a + 1
Next vN2
end_of_for:
i = i + 1
Next vN
You could use a boolean flag - I don't know that it's the accepted method, but I use it from time to time.
Dim skipBool as Boolean = False
For Each vN In Array(dAFLcell, dSFcell, dSOcell, dFIGcell, dIBAcell, dIBXcell)
a = 0 'I think you want this out here, otherwise a will always equal 0
For Each vN2 In Array(AFLcell, SFcell, SOcell, FIGcell, IBAcell, IBXcell)
If Not skipBool Then 'run this stuff only if we don't want to skip it (duh!)
If i = a Then
MsgBox a
skipBool = True 'set skipBool to be True (we want to skip it!)
End If
a = a + 1
End If
Next vN2
i = i + 1
skipBool = False 'reset skipBool for the next go around
Next vN
I'm sure this code can be optimized a bit further (and to be honest, I haven't tested it), but it looks like this is what you're going for.
To be honest, the only problem might be that a = 0 was inside the second for loop, and that's why you weren't getting the results you expected. It's been a while since I've used VBA (I've only been using VB.NET), so I don't remember the exact syntax there. I'd try fixing that, and going back to the exit for method. If it still doesn't work, my code should.
Here's another possible approach:
Dim vn, Vn2 As Variant
Dim i, min As Integer
vn = Array(dAFLcell, dSFcell, dSOcell, dFIGcell, dIBAcell, dIBXcell)
Vn2 = Array(AFLcell, SFcell, SOcell, FIGcell, IBAcell, IBXcell)
If UBound(vn) <= UBound(Vn2) Then
min = UBound(vn)
Else
min = UBound(Vn2)
End If
For i = LBound(vn) To min
If vn(i) = Vn2(i) Then
MsgBox vn(i)
Exit For
End If
Next i

How to terminate a do loop?

I am writing a very basic Fortran Code to create the Ising model. However, I am stuck at the very last step - repeat the calculation until the most stable condition is achieved.
do
!Calculation (omitted here)
!Making a decision
if (E1 /= -64) then !not yet stable
if(dE > 0.0) then
call seed
call random_number(prob) ! random generate a number which is 0 <= Prob <= 1
Print *, prob
if(Prob < exp(-dE/T)) then
!do nothing as the flip was made
else
mat(b,c) = -mat(b,c) !flip the sign back, i.e. reject the change; only accept with probability of exp(-dE/T)
end if
else
end if !Since the sign has changed already, if dE<0, the move must be accepted. Therefore no additional move should be taken
else
end do
end if
end do
Apparently, Fortran doesn't like the second last end do statement as I didn't defined do at that particularly. All I want is to exit the do loop once E1 == -64.
In Fortran you can exit a do loop at any time using the exit statement.
do
...
if (condition) exit
end do
If your do loop is labelled, use the label in the exit statement too
outer: do
inner: do
...
if (condition) exit outer
end do inner
end do outer
Fortran 2008 allows the exit statement for other constructs too.
You should be able to use a while loop.
while (E1 [.ne. OR /=] -64) do
[your code]
end do
This requires E1 be updated inside the loop. Without this update, E1 will always not equal -64 and cause an infinite loop. Your code doesn't explicitly show this happening. I assume it does, but it's something to keep in mind.

How to jump out of the outer loop if inner' for 'loop is executed in lua

S = 'MSH, mdmOBX, TXA'
for u in string.gmatch(S, "([^,%s]+)"),1 do
l[k] = u
for a in string.gmatch(u,'.-([A-Z].*)'),1 do
g[z] = a
print(g)
_G["Map"..l[k]](Msg[g[z]],R[1])
end
_G["Map"..l[k]](Msg[l[k]],R[1])
end
I have above code, I want statement outside of inner loop to be executed only if inner for loop is not executed, I tried using 'break' keyword but that did not work and control was passed to outerloop .how to fix this?
Since Lua 5.2, you can just
goto label -- This statement goes to the jump-label label
::label:: -- The jump-label label
Using a flag variable which is checked after each loop which could set it for early bailout using successive break-statements is a classic of those fearing goto, or being condemned by lack of it.
local earlyreturn
for u in ... do
for a in ... do
if ... then
earlyreturn = true
break
end
end
if earlyreturn then
break
end
end
Anyway, you could also wrap your loops in a function and use return.
function(...)
for u in ... do
for a in ... do
if ... then
return
end
end
end
end(...)
Technically, to answer the "how to break out multiple loops": you can use a goto statement with an appropriately placed label, although it may not be the best solution. How about wrapping the body of the inner loop in an if instead?

Classic ASP - BOF

I am trying to run two WHILE NOT loops for a recordset. One of the loops counts the number of items whilst the other prints the results. I cannot alter the SQL query, so this is the counting method I'm left with.
setPeopleCount = 0
While NOT rsSetContents.EOF
setPeopleCount = setPeopleCount + 1
rsSetContents.MoveNext
Wend
While NOT rsSetContents.EOF
Response.Write rs.Fields("exampleItem")&"<br>"
rsSetContents.MoveNext
Wend
My problem is running the two loops. After the first loop has finished the count, the record cursor is at the end of the file, so when the next loop needs to run - it doesn't because EOF is true.
How can I reset the cursor back to the beginning of the file so the second loop can run?
You can use MoveFirst.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms677527(v=vs.85).aspx
Could you not count on the bottom loop? Or perhaps read the records into an object array then you are free to iterate over it as many times as u want
The MoveFirst requires proper cursor on the recordset - if for example you'll change to different database the default cursor might change and the code might fail.
I would suggest you to store the values while counting, thus save the second loop:
setPeopleCount = 0
Dim exampleItems()
ReDim exampleItems(-1)
While NOT rsSetContents.EOF
setPeopleCount = setPeopleCount + 1
ReDim Preserve exampleItems(UBound(exampleItems) + 1)
exampleItems(UBound(exampleItems)) = rs("exampleItem")
rsSetContents.MoveNext
Wend
'instead of a loop, just this:
Response.Write(Join(exampleItems, "<br />"))

Loops in ada and the implementation

Below is a piece of code shown and doubts are regarding the implementation of loops
C := character'last; --'// SO code colorizer hack
I := 1;
K : loop
Done := C = character'first; --'
Count2 := I;
Exit K when Done;
C := character'pred(c); --'
I := I + 1;
end loop K;
Can anyone please tell me what does 'K' stands for.I guess its not a variable.How does 'K' control the execution of the loop?
K is the name of the loop. The end loop and Exit statements refer to that name, to make it clear what loop is being exited.
The Ada Reference Manual calls it a "loop_statement_identifier".
As noted, K is the loop's label. It allows you to identify a particular loop to aid readability, and also to selectively exit a specific loop from a set of nested enclosing ones (i.e. being a "goto"...shhh! :-)
Here's a contrived example (not compiled checked):
S : Unbounded_String;
F : File_Type;
Done_With_Line : Boolean := False;
All_Done : Boolean := False;
begin
Open(F, In_File, "data_file.dat");
File_Processor:
while not End_Of_File(F) loop
S := Get_Line(F);
Data_Processor:
for I in 1 .. Length(S) loop
Process_A_Character
(Data_Char => Element(S, I), -- Mode in
Line_Done => Done_With_Line, -- Mode out
Finished => All_Done); -- Mode out
-- If completely done, leave the outermost (file processing) loop
exit File_Processor when All_Done;
-- If just done with this line of data, go on to the next one.
exit Data_Processor when Done_With_Line;
end loop;
end loop File_Processor;
Close(F);
end;
K is essentially the name of the loop. The exit k tells the code to stop looping and go to the next statement after loop k ends.
You usually don't need to name loops, as you can just say exit and it will exit the enclosing loop. However, if you have a loop nested inside another loop, and you'd like to exit not the one immediately around the exit statement, but the outermost one, then doing something like this may be required.
K is a label that names the loop. Wow, it has been a long time since I've seen any Ada...

Resources