- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
I try to define macro variables in an iterative loop. An altough the code underneath does what it should (SAS 9.4), we can expect a warning message "apparent symbolic references not resolved". Actually I have no idea how a more elegant solution might look. Can you help me?
%MACRO a(XVAR1=, CCENT=, GCENT=);
%MACRO NAMEP(prefix,maxnum);
%DO i=1 %to &maxnum;
&prefix&i
%END;
%MEND NAMEP;
%if %sysevalf(%superq(XVAR1)=,boolean) = 0 %then %do;
%let NXVAR1 = 1;
%do %while(%length(%scan(&XVAR1,&NXVAR1)));
%let NXVAR1 = %EVAL(&NXVAR1 + 1);
%end;
%Let NXVAR1 = %eval(&NXVAR1 -1);
%Do N1 = 1 %to &NXVAR1;
%Let a=%scan(&XVAR1,&N1);
%Let b=%index(&CCENT,&a);
%Let c=%index(&GCENT,&a);
%if &b > 0 %then %do;
%Let X1&N1 = &a.cc;
%end;
%else %if &c > 0 %then %do;
%Let X1&N1 = &a.gc;
%end;
%else %do;
%Let X1&N1 = &a;
%end;
%end;
%let XVAR1n = %namep(&X1,&NXVAR1);
%end;
%else %do;
%Let XVAR1n = ;
%end;
%put &XVAR1n;
%mend a;
%a(XVAR1=xvar1a xvar1b, CCENT=xvar1b, GCENT=xvar1a);
Bye, Daniel
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
First as was mentioned by @ballardw embedded macro definitions are not needed and almost always counter productive. The macro definitions would appear as:
%MACRO NAMEP(prefix,maxnum);
%DO i=1 %to &maxnum;
&prefix&i
%END;
%MEND NAMEP;
%MACRO a(XVAR1=, CCENT=, GCENT=);
%local xvar1n;
....
The better news is that you don't need the %NAMEP macro anyway. Let's look at your other code a bit. This portion counts the number of words in &XVAR1.
%let NXVAR1 = 1;
%do %while(%length(%scan(&XVAR1,&NXVAR1)));
%let NXVAR1 = %EVAL(&NXVAR1 + 1);
%end;
%Let NXVAR1 = %eval(&NXVAR1 -1);
This is simplified with the COUNTW function.
%let NXVAR1 = %sysfunc(countw( &XVAR1));
The call to the %NAMEP is causing an error (unitialized variable because &X1 is not defined). Since you already have a loop. the definition of &XVAR1N can be moved insite the loop.
%else %do;
%Let X1&N1 = &a;
%end;
%let XVAR1n = &xvar1n &&x1&n1;
%end;
%end;
%else %do;
%Let XVAR1n = ;
%end;
%put &XVAR1n;
%mend a;
Notice that &XVAR1N is initialized as a local macro variable just below the macro statement. Other cleanup in the macro is possible, but this should get you started.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
I can't work out exactly what you're trying to do, but is it simply a case of:
%let XVAR1n = %namep(X1, &NXVAR1);
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
What exactly is it your trying to do? I can guarentee you thre is a far simpler and easier to maintain way of doing things thatn that, be it re-modelling your data, or using inbuilt SAS functionality. Creating endless macro lists, macros and such like is a recipe for obfuscatd, unmaintable code which will fall over every time you run it.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Defining a macro to include another macro, especially one such as your NAMEP that has no dependencies on the parameters of the outmacro is poor practice. As a minimum you waste compute cycles recompiling it everytime the outer macro executes.
And it really helps to provide an example of what you expect this macro to produce.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
First as was mentioned by @ballardw embedded macro definitions are not needed and almost always counter productive. The macro definitions would appear as:
%MACRO NAMEP(prefix,maxnum);
%DO i=1 %to &maxnum;
&prefix&i
%END;
%MEND NAMEP;
%MACRO a(XVAR1=, CCENT=, GCENT=);
%local xvar1n;
....
The better news is that you don't need the %NAMEP macro anyway. Let's look at your other code a bit. This portion counts the number of words in &XVAR1.
%let NXVAR1 = 1;
%do %while(%length(%scan(&XVAR1,&NXVAR1)));
%let NXVAR1 = %EVAL(&NXVAR1 + 1);
%end;
%Let NXVAR1 = %eval(&NXVAR1 -1);
This is simplified with the COUNTW function.
%let NXVAR1 = %sysfunc(countw( &XVAR1));
The call to the %NAMEP is causing an error (unitialized variable because &X1 is not defined). Since you already have a loop. the definition of &XVAR1N can be moved insite the loop.
%else %do;
%Let X1&N1 = &a;
%end;
%let XVAR1n = &xvar1n &&x1&n1;
%end;
%end;
%else %do;
%Let XVAR1n = ;
%end;
%put &XVAR1n;
%mend a;
Notice that &XVAR1N is initialized as a local macro variable just below the macro statement. Other cleanup in the macro is possible, but this should get you started.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for the valuable thoughts and the time that you have spent on my problem.
For the sake of completeness here the working code:
%MACRO a(XVAR1=, CCENT=, GCENT=);
%local xvar1n;
%if %sysevalf(%superq(XVAR1)=,boolean) = 0 %then %do;
%let NXVAR1 = %sysfunc(countw(&XVAR1));
%Do N1 = 1 %to &NXVAR1;
%Let a=%scan(&XVAR1,&N1);
%Let b=%index(&CCENT,&a);
%Let c=%index(&GCENT,&a);
%if &b > 0 %then %do;
%Let X1&N1 = &a.cc;
%end;
%else %if &c > 0 %then %do;
%Let X1&N1 = &a.gc;
%end;
%else %do;
%Let X1&N1 = &a;
%end;
%let XVAR1n = &XVAR1n &&X1&N1;
%end;
%end;
%else %do;
%Let XVAR1n = ;
%end;
%put &XVAR1n;
%mend a;
%a(XVAR1=xvar1a xvar1b, CCENT=xvar1b, GCENT=xvar1a);