This question already has answers here:
Decrementing a loop counter as loop is executing
(3 answers)
Closed 7 years ago.
Can someone explain me this?
for i = 1, 5 do
print(i)
i = i - 1
print(i)
end
Output is:
1
0
2
1
3
2
and so forth
I exspected i to alter between 1 and 0. But obviously it keeps increasing as if I did not change it at all. What's going on?
I have to delete an i'th table element every now and then. So the next element to process would be i again. In C I would just write --i at the end of my loop content. Any official way in lua? :)
The loop index (i in your case) is a variable local to the body of the loop, so any modifications you do to it have no effect on the loop conditions or the next element being processed (for the for loop).
If you need to have better control over the index to delete elements and keep processing, you should use the while loop form. See For Statement section for details.
What about using a while(true) loop instead? Then you'll have to break manually, but that might work.
local i = 5
while(true) do
print(i)
i = i - 1
if (i == 0) then break; end
end
Attempting to set the loop control variable causes a failsafe behavior.
I can't find it in the Language Incompatibility section of recent versions of the manual but I recall it being listed somewhere as a change. It was more of a formalization of previous undefined behavior.
If you are really curious, see the listing of your program from luac. The loop control variable is given an internal name so it can't be changed. If the same name is used in an assignment, a local variable is synthesized as a stand-in. It prevents unintentionally causing the for to become infinite.
You need another kind of loop.
Related
I have been having this issue with p5js on multiple coding projects. Once I have two or more for-loops (they are not nested) in the sketch, nothing will execute AFTER the loop.
I worked around this issue in previous sketches by changing around the order and putting the for-loops last.
However, for my current sketch, I need a for-loop to build on information about arrays in the previous loop. I've even tried adding a simple shape after the loop and before. And the shape will only execute and render on the sketch when it is included BEFORE.
The code for my sketch is quite long but if it will be useful to include it I can.
Thanks for your help.
If the code after a loop is never executed it might mean that your loop never finishes.
I'd recommend using console.log() to debug instead of drawing shapes. This way you can also debug inside the for loop and see if it works correctly.
For example, you can do something like this
console.log("Before loop");
for (let i=0; i<5; i++) {
console.log(`Inside loop. Iteration ${i}`);
}
console.log("After loop");
This code will print
Before loop
Inside loop. Iteration 0
Inside loop. Iteration 1
Inside loop. Iteration 2
Inside loop. Iteration 3
Inside loop. Iteration 4
After loop
As you can see, it's very easy with this code to see that the log before the loop is executed, that the loop executes 5 times and finally the log after the loop is executed.
Put something like this in your code and it will help looking where the code fails.
I'm trying to find a more efficient and speedier way (if possible) to pull subsets of observations that meet certain criteria from multiple hospital claims datasets in SAS. A simplified but common type of data pull would look like this:
data out.qualifying_patients;
set in.state1_2017
in.state1_2018
in.state1_2019
in.state1_2020
in.state2_2017
in.state2_2018
in.state2_2019
in.state2_2020;
array prcode{*} I10_PR1-I10_PR25;
do i=1 to 25;
if prcode{i} in ("0DTJ0ZZ","0DTJ4ZZ") then cohort=1;
end;
if cohort=1 then output;
run;
Now imagine that instead of 2 states and 4 years we have 18 states and 9 years -- each about 1GB in size. The code above works fine but it takes FOREVER to run on our non-optimized server setup. So I'm looking for alternate methods to perform the same task but hopefully at a faster clip.
I've tried including (KEEP=) or (DROP=) statements for each dataset included the SET statement to limit the variables being scanned, but this really didn't have much of an impact on speed -- and, for non-coding-related reasons, we pretty much need to pull all the variables.
I've also experimented a bit with hash tables but it's too much to store in memory so that didn't seem to solve the issue. This also isn't a MERGE issue which seems to be what hash tables excel at.
Any thoughts on other approaches that might help? Every data pull we do contains customized criteria for a given project, but we do these pulls a lot and it seems really inefficient to constantly be processing thru the same datasets over and over but not benefitting from that. Thanks for any help!
I happend to have a 1GB dataset on my compute, I tried several times, it takes SAS no more than 25 seconds to set the dataset 8 times. I think the set statement is too simple and basic to improve its efficient.
I think the issue may located at the do loop. Your program runs do loop 25 times for each record, may assigns to cohort more than once, which is not necessary. You can change it like:
do i=1 to 25 until(cohort=1);
if prcode{i} in ("0DTJ0ZZ","0DTJ4ZZ") then cohort=1;
end;
This can save a lot of do loops.
First, parallelization will help immensely here. Instead of running 1 job, 1 dataset after the next; run one job per state, or one job per year, or whatever makes sense for your dataset size and CPU count. (You don't want more than 1 job per CPU.). If your server has 32 cores, then you can easily run all the jobs you need here - 1 per state, say - and then after that's done, combine the results together.
Look up SAS MP Connect for one way to do multiprocessing, which basically uses rsubmits to submit code to your own machine. You can also do this by using xcmd to literally launch SAS sessions - add a parameter to the SAS program of state, then run 18 of them, have them output their results to a known location with state name or number, and then have your program collect them.
Second, you can optimize the DO loop more - in addition to the suggestions above, you may be able to optimize using pointers. SAS stores character array variables in memory in adjacent spots (assuming they all come from the same place) - see From Obscurity to Utility:
ADDR, PEEK, POKE as DATA Step Programming Tools from Paul Dorfman for more details here. On page 10, he shows the method I describe here; you PEEKC to get the concatenated values and then use INDEXW to find the thing you want.
data want;
set have;
array prcode{*} $8 I10_PR1-I10_PR25;
found = (^^ indexw (peekc (addr(prcode[1]), 200 ), '0DTJ0ZZ')) or
(^^ indexw (peekc (addr(prcode[1]), 200 ), '0DTJ4ZZ'))
;
run;
Something like that should work. It avoids the loop.
You also could, if you want to keep the loop, exit the loop once you run into an empty procedure code. Usually these things don't go all 25, at least in my experience - they're left-filled, so I10_PR1 is always filled, and then some of them - say, 5 or 10 of them - are filled, then I10_PR11 and on are empty; and if you hit an empty one, you're all done for that round. So not just leaving when you hit what you are looking for, but also leaving when you hit an empty, saves you a lot of processing time.
You probably should consider a hardware upgrade or find someone who can tune your server. This paper suggests tips to improve the processing of large datasets.
Your code is pretty straightforward. The only suggestion is to kill the loop as soon as the criteria is met to avoid wasting unnecessary resources.
do i=1 to 25;
if prcode{i} in ("0DTJ0ZZ","0DTJ4ZZ") then do;
output; * cohort criteria met so output the row;
leave; * exit the loop immediately;
end;
end;
I was asked this question in an interview, here it goes
'You have written for loop from 1 to 100, but I want to run the for loop from 70 to 100, ignoring previous iteration from 1 to 69. You are not allowed to change anything in the script, how can you automate this in QTP?'
Can somebody please tell me how I can achieve this?
Please follow the below steps and you will be able to work with for loop :
Step 1. Put a break point where the loop starts.
Step 2. Run the Script and when it stops at break point, go to view-->debug-->Console and change the value of your iterator variable from 0(start value) to 70.
example : i = 70
Step 3. Run the script and you will achieve your target.
You could always check the value of your iteration variable as the first step in your 'For' loop and if the value is 1, change it to 70
My code, as written, works for all the ways I've tested it. I have two questions though. First, Why in the blue blazes do I HAVE to use Do While loops instead of For loops in my code? I've searched Everywhere I can to help me on this issue. I can't reinstall excel, but I've reset as many of the settings as I can, but, invariably, the compiler skips over every for loop I have that isn't a for each loop... Except the first for loop in my programming... It is the weirdest and most bizarre behavior I have ever seen. I have used step through (F8) 10000 times to try and figure out why it keeps skipping. But every single time i make a for loop, it doesn't even run the first line of it.
To be clear, every place I have a Do While ... Loop, it SHOULD be a For Next. But making this change breaks the code every time because every spot the do while is changed to for, the code is skipped entirely. Even if I reset the i value to 0. The issue happens even if I have a different iterator for each loop.
Running w8 on an Intel i5 with Office 2010.
For i=1 To i = 100
If (i >= startRow And i <= stopRow And Not rowDone(i) And Not i = colFocus) Then
colCurPayAmounts(i) = S_Debt.Cells(i, 5)
Else
colCurPayAmounts(i) = 0
End If i = i + 1
Next i
The problem is it should be For i = 1 To 100 and not For i = 1 To i = 100 #Rory
I want to stop the execution, when the loop has been executed n number of times. I don't want to use the conditional breakpoint using value of loop-counter because initial value of loop-counter is different at different time of run.
You need to use the ignore command. Set a breakpoint at the relevant place in your loop and then use ignore to indicate how many times that the breakpoint is to be ignored.
Syntax, as per help ignore is:
Set ignore-count of breakpoint number N to COUNT. Usage is `ignore N
COUNT'.