BookmarkSubscribeRSS Feed
SASPhile
Quartz | Level 8
Hi All,

the following code works.
data temp;
do i= 1 to 5 ,7,9; (Non continuous loop)
m=i+1;
end;
run;


if I use the same logic in macros it fails

%macro temp1;
data temp;
%do i= 1 %to 5,7,9;
m=&i+1;
%end;
run;
%mend temp1;
%temp1;

What could be the reason?

Thanks all for your time.
SASPHILE!
16 REPLIES 16
kassimorra
Calcite | Level 5
Hi Phille,

I read some papers about the %do statement and I didn´t find anything about this way of using %do statement with specific cases. Maybe, %do in macro function don´t have this functionallity. When I tried to run, he don´t recognize the %do parameter.

You could resolver this problem using an array to perfom the specific calculation with 5, 7 and 9.

Other think, the do statement on the sas code, execute 7 times ( he executes 1, 2, 3, 4, 5, 7, 9) and not 3 times ( using 5, 7, 9), as it appears to be created for.

If you find a positiver answer to your problem, please send it here !!!

Regards.

Kassim
Brazil
ieva
Pyrite | Level 9
Try this:

%macro temp1;
data temp1;
%do i= 1 %to 9;
m=&i+1;
if &i in (1:5, 7, 9) then output;
%end;
run;
%mend temp1;
%temp1;

Maybe not the most elegant solution, but it works.

I don't know why it doesn't work in a regular way.
ieva
Pyrite | Level 9
But maybe the answer is much simpler. In this case we don't have to use %do but just do;

%macro temp1;
data temp1;
do i= 1 to 5, 7,9;
m=i+1;
output;
end;
run;
%mend temp1;
%temp1;

It works fine. So I guess the question now is when should we use '%do' and when 'do'. Should be careful about that.
deleted_user
Not applicable
There are two parts to this.

 

Firstly your non-continuous do loop is not doing what you think it is. The syntax for the do statement is:

DO index-variable=specification-1 <, . . . specification-n>;

where

specification

  denotes an expression or a series of expressions in this form

start

 

You've given, excuse the psuedo-markup, the following:



  

  

  



 

Next, the syntax for %DO (Iterative) does not support multiple specifications and is given as

%DO macro-variable=start %TO stop <%BY increment>;

 

The equivalent macro code would be

 

%macro temp1;

data temp;

%do i= 1 %to 5;

  m=&i+1;

%end;

%do i=7 %to 9 %by 2;

  m=&i+1;

%end;

run;

%mend temp1;

%temp1;

 

which would be resolved to the following executable code:

 

data temp;

  m=1+1;

  m=2+1;

  m=3+1;

  m=4+1;

  m=5+1;

  m=7+1;

  m=9+1;

run;

 

If you want to read the manual it is available here.

 

I'm still mystified by what you are trying to accomplish, but hope this helps,

 

ProcMe
SASPhile
Quartz | Level 8
Hello Procme,
There is a situation where in I have to loop through many iterations.But the case for the looping is non continous. And also the variable names are to be changed dynamically for every loop increment. Thats the reason I have to use the macro loop counter.
So the case is i will have a contimnous looping from 2 to 13 and then 17,18,21 and 29.
I was looking for a workaround in this case.
Thanks for your time.
SASPHILE
deleted_user
Not applicable
Is this the sort of thing you were after?

/*Loop rule set*/
data loops;
input from to;
infile cards missover;
cards;
1 12
17 18
21
23
;
run;
/* Play data, something to process */
data have;
do i = 1 to 50;
output;
end;
run;

%macro doloops(data=have, out=want, loopset=loops, key=i, action=output);
/*Read the loop rule set into memory */
data _null_;
set &loopset end=eof;
call symput('loop_from_' || compress(_n_), compress(from));
if to eq . then
call symput('loop_to_' || compress(_n_), compress(from));
else
call symput('loop_to_' || compress(_n_), compress(to));
if eof then
call symput('loop_count', compress(_n_));
run;
/* Process the specified dataset */
data &out(drop=_i);
set &data;
%do _loop = 1 %to &loop_count;
%let _from = &&&loop_from_&_loop;
%let _to = &&&loop_to_&_loop;
do _i = &_from to &_to;
if &key = _i then do;
&action;
end;
end;
%end;
run;

%mend doloops;

%doloops(data=have, out=want, loopset=loops, key=i, action=output);

Gives output for obs 1-12, 17-18, 21, 23.

ProcMe
deleted_user
Not applicable
... or

data &out(drop=_i);
set &data;
do _i =
%do _loop = 1 %to &loop_count;
%let _from = &&&loop_from_&_loop;
%let _to = &&&loop_to_&_loop;

%if &_loop lt &loop_count %then &_from to &_to,
%else &_from to &_to ;
%end;
;
if &key = _i then do;
&action;
end;
end;

run;

ProcMe
SASPhile
Quartz | Level 8
Proc me,
Here is the case:
I would want to create datasets temp2 to temp14 and then temp16,temp17 and temp41
In the following case the loop goes through 2to41 and creates empty datasets like temp18 temp19.......... etc which i dont need.
the logic is based on the where condition and _temg001 have values only from 2 to 14 and 16,17 and 41.

%macro flatten;
%do i= 2 %to 41;
data temp&i;
set allvar.Duphic_20080110(keep= assignment_reassignment_date
HIC _TEMG001 month ma_pd_ind);
where _TEMG001=&i and ma_pd_ind='PD' and month<10;
if &i in (2:14,16,17,41) then output;
%end;
run;
%mend flatten;
%flatten;
Thanks for your time.
SASPHILE
sbb
Lapis Lazuli | Level 10 sbb
Lapis Lazuli | Level 10
An approach I used frequently is to drive a macro execution with a DATA step and CALL EXECUTE.

An oversimplified example:

%MACRO X(VALUE);
%PUT >INFO> MACRO X INVOKED WITH VALUE: &VALUE;
%MEND X;
DATA _NULL_;
DO I=1 TO 41;
IF I IN (1,15) OR (18 LE I LE 40) THEN CONTINUE;
CALL EXECUTE('%X(' !! I !! ')');
END;
RUN;

As has been conveyed, the %IF / %END is not equal to the DO / END behavior and syntax within the SAS language, and so there are ways to work within the current system.

Scott Barry
SBBWorks, Inc.
deleted_user
Not applicable
Would this do the trick?

data loops;
input from to;
infile cards missover;
cards;
1 12
17 18
21
23
;
run;

data have;
do _TEMG001 = 1 to 50;
output;
end;
run;

%macro doloops(data=have, out=want, loopset=loops, key=i);

data _null_;
set &loopset end=eof;
call symput('loop_from_' || compress(_n_), compress(from));
if to eq . then
call symput('loop_to_' || compress(_n_), compress(from));
else
call symput('loop_to_' || compress(_n_), compress(to));
if eof then
call symput('loop_count', compress(_n_));
run;
data
%do _loop = 1 %to &loop_count;
%do _outds = &&&loop_from_&_loop %to &&&loop_to_&_loop;
&out._&_outds.(drop=_i)
%end;
%end;
;
set &data;
do _i =
%do _loop = 1 %to &loop_count;

%if &_loop lt &loop_count %then &&&loop_from_&_loop to &&&loop_to_&_loop, ;
%else &&&loop_from_&_loop to &&&loop_to_&_loop ;

%end;
;
%do _loop = 1 %to &loop_count;
%do _outds = &&&loop_from_&_loop %to &&&loop_to_&_loop;
if &key = &_outds and _i = &_outds then output &out._&_outds;
%end;
%end;
end;

run;

%mend doloops;

%doloops(data=have, out=want, loopset=loops, key=_TEMG001);

ProcMe
deleted_user
Not applicable
... and you can get the loops dataset using something like this:

data loop_source;
do i = 1 to 9, 12, 16 to 18, 22;
output;
end;
run;

data loops(keep=from to);
set loop_source end=eof;
retain from 0;
retain to 0;
retain last_i 0;
if _n_ = 1 then from = i;
else do;
last_i = lag(i);
if last_i ne . and last_i lt i-1 then do;
to = last_i;
output;
from = i;
end;
end;
if eof then do;
to = i;
output;
end;
run;

ProcMe
Patrick
Opal | Level 21
Just two more variants how to do it:
HTH
Patrick


/* variant 1: %do %while with %scan */
%macro CreateTempDSVers1(ind=);
%let i=1;
%do %while(%scan(&ind,&i) ne );
data TempDS%scan(&ind,&i);
var='hello world';
run;
%let i=%eval(&i+1);
%end;
%mend;

%CreateTempDSVers1(ind=2 3 4 5 6 7 8 9 10 11 12 13 14 16 17 41)


/* variant 2: Call Execute */
%macro CreateTempDSVers2(ind);
data TempDS&ind;
var='hello world';
run;
%mend;

data _null_;
do i=2 to 14,16,17,41;
call execute(cats('%CreateTempDSVers2(',i,')'));
end;
run;
SASPhile
Quartz | Level 8
Thanks for the help.
But by invoking macros for looping causes other advanced functionality it will be 1 observation behind.
Patrick
Opal | Level 21
Does this the job for you?

data have;
do i= 2 to 14,16,17,41;
_TEMG001=i; ma_pd_ind='PD'; month=7;output;
_TEMG001=i; ma_pd_ind='xx'; month=7;output;
_TEMG001=i; ma_pd_ind='PD'; month=10;output;
end;
run;

proc sql noprint;
select distinct _TEMG001, cats('work.temp',_TEMG001), cats('when(',_TEMG001,') output temp',_TEMG001,';')
into :IndList separated by ' ', :OutDS separated by ' ', :SelectDs separated by ' '
from have
order by _TEMG001;
quit;
%put OutDs =%bquote(&OutDs);
%put SelectDs=%bquote(&SelectDs);

data &OutDS;
set have;
where ma_pd_ind='PD' and month<10;
select (_TEMG001);
&SelectDs
otherwise;
end;
run;

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 16 replies
  • 1656 views
  • 0 likes
  • 7 in conversation