## Do UNTIL Loop with conditional stop

Solved
Occasional Contributor
Posts: 12

# Do UNTIL Loop with conditional stop

Hello, I wish to use a do until loop until the condition that there is a unique drug for each observation with some form of randomization for 3 repetitions is met.

``````data units;
do Unit = 1 to 8;
output;
end;
run;``````

The top shows dummy data. I will explain the overall problem that I have and how I'm trying to solve it.

id           Drug_1 Drug_2 Drug_3

 1 2 4 3 2 1 2 4 3 3 1 2 4 4 1 2 5 4 3 1 6 2 3 1 7 1 4 3 8 3 2 4

In the second-fourth column, 1 shows up 2 times, 2 shows up 2 times, 3 shows up 2 times, and 4 shows up 2 times. They also do not repeat through each observation. In this example, the groups (1-4) are evenly distributed but I'd like to have the option to change their sizes depending on the condition

To solve this, I am trying to cycle through different seeds to be able to get the desired outcome. To accomplish this, I created two local macros. n is to cycle through seed numbers and stop is to indicate when I've obtained the desired dataset. This outcome is shown through the sum of indicator being 0 or through drug 1 - drug 3 not equal to one another.

``````%macro m(start);

%local n;
%let n=&start;

%local stop;
%let stop = 0;

%do %until(stop ne 0);

proc surveyselect data=units groups=(2,2,2,2) seed=&n reps=3 noprint
out=assignedUnits(rename=groupId=drug);
run;

proc sort data=assignedUnits;
by Unit;
run;

proc transpose data=assignedUnits out=wide1(drop=_NAME_ _LABEL_) prefix=drug_;
by Unit;
var drug;
run;

data desiredData;
set wide1;

indicator=.;
if drug_1 ne drug_2 and drug_1 ne drug_3 and drug_2 ne drug_3 then drug = 0;
else indicator=1;

st=.;
if drug_1 ne drug_2 and drug_1 ne drug_3 and drug_2 ne drug_3 then st = 0;
else %let stop=%eval(&stop+1);
run;

proc print data=desiredData;
sum indicator;
title "Seed number &n";
run;

%let n=%eval(&n+1);
%end;
%mend m;``````

Unfortunately, the second if statement is not working. I want it to change the local variable stop to when the if statement is true but it has not been performing as desired. Is there any way to perform this?

Accepted Solutions
Solution
‎01-16-2018 04:40 PM
Super User
Posts: 2,061

## Re: Do UNTIL Loop with conditional stop

[ Edited ]

Nope, won't work. If i can guess, You may have to change the part of the  program to this :

``````data desiredData;
set wide1 end=last;

indicator=.;
st=.;
if (drug_1 ne drug_2) and (drug_1 ne drug_3) and (drug_2 ne drug_3) then do;
drug = 0;
st = 0;
end;
else do;
indicator=1;
end;
sum_indicator+indicator;
if last then do; if sum_indicator=0 then /*your call symputx goes here*/

run;``````

All Replies
Super User
Posts: 2,061

## Re: Do UNTIL Loop with conditional stop

That is because you are trying to execute a macro statement at execution time(datastep execution). Unfortunately, that execution

``%let stop=%eval(&stop+1);``

happens at compile time.

Super User
Posts: 6,933

## Re: Do UNTIL Loop with conditional stop

I can't promise this fixes everything, but here are two items that must be changed.

%do %until (stop ne 0);

This comparison will always be true, because STOP does not refer to a DATA step variable named STOP.  Instead, you can use:

%do %until (&stop = 1);

Secondly, the DATA step cannot execute a %LET statement.  This statement is not doing anything when the DATA step executes:

else %let stop = %eval(&stop + 1);

This might be closer to what you want:

else call symputx('stop', '1');

That would assign the macro variable &STOP a value of 1, when the ELSE statement executes.

There may be more, but fixing this would at least be a starting point.

Super User
Posts: 2,061

## Re: Do UNTIL Loop with conditional stop

i tried to fix a bit, see if this helps:

``````%macro m(start);

%local n;
%let n=&start;

%local stop;
%let stop = 0;

%do %until(stop ne 0);

proc surveyselect data=units groups=(2,2,2,2) seed=&n reps=3 noprint
out=assignedUnits(rename=groupId=drug);
run;

proc sort data=assignedUnits;
by Unit;
run;

proc transpose data=assignedUnits out=wide1(drop=_NAME_ _LABEL_) prefix=drug_;
by Unit;
var drug;
run;

data desiredData;
set wide1;

indicator=.;
st=.;
if (drug_1 ne drug_2) and (drug_1 ne drug_3) and (drug_2 ne drug_3) then do;
drug = 0;
st = 0;
end;
else do;
indicator=1;
call symputX('stop',resolve('&stop')+1);
end;

run;

proc print data=desiredData;
sum indicator;
title "Seed number &n";
run;

%let n=%eval(&n+1);
%end;
%mend m;``````
Occasional Contributor
Posts: 12

## Re: Do UNTIL Loop with conditional stop

Thanks, that almost works. Unfortunately, it continues past seed 93 (I verified that it meets the aforementioned conditions). I read that symputX converts it to character. Am I correct in that assertion as could that be why it keeps going?

Super User
Posts: 2,061

## Re: Do UNTIL Loop with conditional stop

Oops, i missed to change this

``	%do %until(stop ne 0);``

to

``	%do %until(&stop ne 0);``

Occasional Contributor
Posts: 12

## Re: Do UNTIL Loop with conditional stop

I apologize, but I saw a major error in my program. The symputX('stop',resolve('&stop')+1); portion should somehow be related to the sum of the indicator variable. Would the following work?

``if sum(indicator) = 0 then call symputX('stop',resolve('&stop')+1);``
Solution
‎01-16-2018 04:40 PM
Super User
Posts: 2,061

## Re: Do UNTIL Loop with conditional stop

[ Edited ]

Nope, won't work. If i can guess, You may have to change the part of the  program to this :

``````data desiredData;
set wide1 end=last;

indicator=.;
st=.;
if (drug_1 ne drug_2) and (drug_1 ne drug_3) and (drug_2 ne drug_3) then do;
drug = 0;
st = 0;
end;
else do;
indicator=1;
end;
sum_indicator+indicator;
if last then do; if sum_indicator=0 then /*your call symputx goes here*/

run;``````

☑ This topic is solved.