LISTSERV at the University of Georgia
Menubar Imagemap
Home Browse Manage Request Manuals Register
Previous messageNext messagePrevious in topicNext in topicPrevious by same authorNext by same authorPrevious page (September 2003, week 4)Back to main SAS-L pageJoin or leave SAS-L (or change settings)ReplyPost a new messageSearchProportional fontNon-proportional font
Date:   Fri, 26 Sep 2003 00:35:29 -0700
Reply-To:   Chang <chang_y_chung@HOTMAIL.COM>
Sender:   "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From:   Chang <chang_y_chung@HOTMAIL.COM>
Organization:   http://groups.google.com/
Subject:   Re: Nested macro question for mavens and gurus
Content-Type:   text/plain; charset=ISO-8859-1

Hi, Ian and mavens and gurus,

Wow! As always, I just learn a lot from Ian's thoughtful code and comments.

His final comment about whether we should use an extra parameter (X) got me thinking. I thought it was a good idea. And after some time, I came up with a little bit of generalization of the loop_through_months macro as in the below. The basic idea is: if we have to use an extra parameter, then let's make the full use of it.

Given the fact that my co-workers do not really appreciate it when I try to think :-), I am not really confident if this is a good idea (hopefully) or a terribly bad one. I really appreciate your comments. Thank you.

Cheers, Chang

macro -------------------------------------------------------- %macro forEach(unit=, from=, to=, invoke=);

%local &unit. start end next;

%let unit = %lowcase(%trim(%left(&unit.)));

%if %index(year month day, &unit.) %then %do;

%let start = %sysfunc(intnx(&unit., %sysfunc(inputn(&from.,date9.)),0)); %let end = %sysfunc(intnx(&unit., %sysfunc(inputn(&to. ,date9.)),0)); %let next = %nrstr(%sysfunc(intnx(&unit.,&&&unit..,0,e)));

%end; %else %if &unit.=number %then %do;

%let start = &from.; %let end = &to.; %let next = %nrstr(&&&unit..);

%end;

%do &unit. = %unquote(&start.) %to %unquote(&end.); %unquote(&invoke.); %let &unit. = %unquote(&next.); %end;

%mend forEach; --------------------------------------------------------------

usage examples (log outputs in comments) --------------------- %macro test(year=); %put ***year=&year.***; %mend test; %forEach( unit=year, from=20mar2000, to=23feb2002, invoke=%nrstr(%test(year=%sysfunc(putn(&year.,year4.)))) ); /* ***year=2000*** ***year=2001*** ***year=2002*** */

%macro test(month=); %put ***month=&month.***; %mend test; %forEach( unit=month, from=01dec1999, to=10feb2000, invoke=%nrstr(%test(month=%sysfunc(putn(&month.,yymmn6.)))) ); /* ***month=199912*** ***month=200001*** ***month=200002*** */

%macro test(day=); %put ***day=&day.***; %mend test; %forEach( unit=day, from=28feb2000, to=02mar2000, invoke=%nrstr(%test(day=%sysfunc(putn(&day.,worddatx.)))) ); /* ***day=28 February 2000*** ***day=29 February 2000*** ***day=1 March 2000*** ***day=2 March 2000*** */

%macro test(number=); %put ***number=&number.***; %mend test; %forEach( unit=number, from=1, to=3, invoke=%nrstr(%test(number=&number)) ); /* ***number=1*** ***number=2*** ***number=3*** */ --------------------------------------------------------------

WHITLOI1@WESTAT.COM (Ian Whitlock) wrote in message news:<569DFDF32A05FC41A33DAA026649A18B08007F@REMAILW2K2>... > Doug, > > I would simplify and speed things up with SAS dates. Following Dennis' > suggestion and using > > %macro loop_through_months(startmon=, endmon=, sas_code_to_loop=); > > %local mon ; > > %do mon = %sysfunc(inputn(01&startmon,date9.)) > %to %sysfunc(inputn(01&endmon,date9.)) ; > > %unquote (&sas_code_to_loop)(mon=&mon) > > %let mon = %sysfunc(intnx(month,&mon,0,e)) ; > %end; > %mend loop_through_months; > > %macro test_macro(mon=); > %put ====> test_macro executing, > curr_yyyymm=%sysfunc(putn(&mon,yymmn6.)) ; > %mend test_macro ; > > > %loop_through_months(startmon=dec2002, > endmon=feb2003, > sas_code_to_loop=%nrstr(%test_macro)) > > Some comments are in order. With all those function calls, is it really > faster? Yes functions have been implemented very efficiently in comparison > with macro code. Why use the end of the month in the incrementation? > Because the iterative loop will add 1 bringing the date to the first of the > month. Why not use %BY 0? Because some Institute programmer checks your > code and refuses to allow %BY 0. > > Should one have the hidden parameter MON? It is questionable. It could be > left out, but my conscience won't let me call macros without passing > parameters. Why didn't I simply make the call > > %loop_through_months(startmon=dec2002, > endmon=feb2003, > sas_code_to_loop=%nrstr(%test_macro(mon=&mon)) > > I didn't want to burden your call with my conscience. Actually this form > may casue more problems than it is worth. I probably would change the call > the design to > > %macro loop_through_months(x= ,startmon=, endmon=, sas_code_to_loop=); > > %local &x ; > > %do &x = %sysfunc(inputn(01&startmon,date9.)) > %to %sysfunc(inputn(01&endmon,date9.)) ; > > > %unquote (&sas_code_to_loop) > > %let &x = %sysfunc(intnx(month,&&&x,0,e)) ; > %end; > %mend loop_through_months; > > %macro test_macro (mon=mon); > %put ====> test_macro executing, > curr_yyyymm=%sysfunc(putn(&mon,yymmn6.)) ; > %mend test_macro ; > > options nomlogic; > %loop_through_months(x=mon, > startmon=dec2002, > endmon=feb2003, > sas_code_to_loop=%nrstr(%test_macro(mon=&mon))) > > Here the parameter, X, allows the user to name the index and then to pass > the required value. Is it worth it? I still am not sure, but it allows the > user to name the index and to pass the value of that index as a parameter. > > > IanWhitlock@westat.com > -----Original Message----- > From: Doug Zirbel [mailto:doug_zirbel@HOTMAIL.COM] > Sent: Wednesday, September 24, 2003 12:56 PM > To: SAS-L@LISTSERV.UGA.EDU > Subject: Nested macro question for mavens and gurus > > > I wrote a macro which loops through "months", each iteration incrementing a > YYYYMM macro variable by 1 month. I want to pass that &YYYYMM to another > macro nested within the loop, but it of course is not cooperating. > > So how do I pass a macro variable created with a %LET to a macro as its > macro parameter? > > Here's the code: > > options nocenter mprint mlogic; > %global curr_yyyymm; > %let curr_yyyymm=; > > /*******************************************/ > /* This is the test macro (with a parameter) to > /* be nested into the macro loop in the next > /* macro. > /*******************************************/ > %macro test_macro; > %put ====> test_macro executing, curr_yyyymm=&curr_yyyymm; %mend; > > > /*******************************************************/ > /* This is the macro that loops through > /* "months" creating a new macro var "curr_yyyymm" > /* which is incremented by 1 month each iteration. > /* Right after it is incremented, it is to pass > /* that macro var to the nested macro. > /*******************************************************/ > %macro loop_through_months(start_yyyymm=, end_yyyymm=, sas_code_to_loop=); > > %let curr_yyyymm = &start_yyyymm; > > /********************************************** > /* Loop, from starting YYYYMM to ending YYYYMM > /* incrementing at the bottom. "DO UNTIL" > /* does its T/F test at the bottom of the loop. > /**********************************************/ > %do %until (&curr_yyyymm > &end_yyyymm); > %put curr_yyyymm=&curr_yyyymm; > /*******************************************/ > /* This macro var holds the test_macro to be > /* passed to the loop and to then be > /* executed before the next loop interation. > /*******************************************/ > &&sas_code_to_loop; > > /*******************************************/ > /* Increment from December (12) to January (01) > /* if necessary after calling nested macro > /*******************************************/ > %if %substr(&curr_yyyymm,5,2) = 12 %then %do; > %let curr_yyyy=%eval(%substr(&curr_yyyymm,1,4) + 1); > %let curr_mm = 01; > %let curr_yyyymm=&curr_yyyy.&curr_mm; > %end; > > /*******************************************/ > /* Increment from one month # to the next # > /* after calling nested macro > /*******************************************/ > %else %do; > %let curr_yyyymm=%eval(&curr_yyyymm + 1); > %end; > > %end; > %mend loop_through_months; > > %loop_through_months(start_yyyymm=200212, > end_yyyymm=200302, > sas_code_to_loop=%test_macro);


Back to: Top of message | Previous page | Main SAS-L page