- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Posted 01-10-2009 11:19 PM
(5061 views)
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!
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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.
%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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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.
%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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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
/*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
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
... 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
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
... 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
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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;
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;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the help.
But by invoking macros for looping causes other advanced functionality it will be 1 observation behind.
But by invoking macros for looping causes other advanced functionality it will be 1 observation behind.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
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;
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;