BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
braam
Quartz | Level 8

Hi all,

 

I would like to make a macro code that repeats another macro. As below, I can do so by using loop1, but the loop1 macro is designed to repeat the macro, rename, specifically. Rather, I would like to have a repeating macro code that can be generalized to any macro. Could anybody please check why my macro, loop2, doesn't work?

 

To make the issue clearer, I brought a very simple example: The situation here is that I would like to repeat the renaming macro code over a list of variables. Though renaming is actually not the issue I've been facing, the solution to this can solve my own issue.

 

I first make the rename macro (I made this macro to rename one variable at a time):

 

%macro rename (var= , prefix= );
data temp; set temp;
rename &var= &prefix.&var.;
run;
%mend;

 

Then I make the looping macro to repeat the above over a list of variables.

 

%macro loop1 (list);
%let N= %sysfunc(countw(&list)); 
%do x= 1 %to &N;
%let xth_var= %scan(&list, &x);
%rename(var= &xth_var., prefix= test_);
%end;
%mend;

 

The below code confirmed that all of the above codes are correct.

 

data temp; set sashelp.class; run;
proc print; run; *original variable names;
%loop1 (list= name sex age height weight);
proc print; run; *new variable names;

 

Here is the trick issue I've been struggling with: I wanted to make my looping macro like this:

 

%macro loop2 (list=, statement=);
%let N= %sysfunc(countw(&list)); 
%do x= 1 %to &N;
%let xth_var= %scan(&list, &x);
&STATEMENT;
%end;
%mend;

 

The advantage of having the STATEMENT argument in the loop2 is that I can apply loop2 to any macro to repat it. But the below code doesn't work.

%loop2 (list= name sex age height weight,
STATEMENT= %nrstr( %rename(var= &xth_var., prefix= test_); )
);
proc print; run;

 

The message I've got: 

 

%loop2 (list= name sex age height weight,
STATEMENT= %nrstr( %rename(var= &xth_var., prefix= test_); )
);
NOTE: Line generated by the macro variable "STATEMENT".
1 %rename(var= &xth_var., prefix= test_);
-
180

Thanks a lot in advance for your insights!

 

1 ACCEPTED SOLUTION

Accepted Solutions
Astounding
PROC Star
First, note that you should change your plan. If you have 100 variables to rename, you run through 100 DATA steps. The time that takes can add up. SAS knows how to perform 100 renames in a single DATA step.

To solve your original problem, this might work:

%unquote(&STATEMENT) ;

Try it and see. And to help diagnose the problem add this ahead of time:

options mprint;

View solution in original post

9 REPLIES 9
braam
Quartz | Level 8
I'm sorry, but the issue is not specifically about renaming. I would like to make a repeating macro that can be applied to any macro. Hope that I didn't misunderstand you.
Kurt_Bremser
Super User

@braam wrote:
I'm sorry, but the issue is not specifically about renaming. I would like to make a repeating macro that can be applied to any macro. Hope that I didn't misunderstand you.

You can store macro names and parameter lists as character variables in a dataset. Then you use this dataset to call the macro(s):

data _null_;
set this_dataset;
call execute(cats('@nrstr(%',macroname,'(',paramlist,'))'));
run;

 

Astounding
PROC Star
First, note that you should change your plan. If you have 100 variables to rename, you run through 100 DATA steps. The time that takes can add up. SAS knows how to perform 100 renames in a single DATA step.

To solve your original problem, this might work:

%unquote(&STATEMENT) ;

Try it and see. And to help diagnose the problem add this ahead of time:

options mprint;
s_lassen
Meteorite | Level 14

This is not a good way to do the actual job you are doing, but I assume it is just a test/demo. Anyway, you can make your %LOOP2 macro work if you write it like this:

%macro loop2 (list=, statement=);
%let N= %sysfunc(countw(&list)); 
%do x= 1 %to &N;
%let xth_var= %scan(&list, &x);
%unquote(&STATEMENT);
%end;
%mend;

The %UNQUOTE function will resolve the macro-quoted value.

 

braam
Quartz | Level 8

Thanks for your help. It actually worked. Then, I wanted to apply the same thing to my original issue, but somehow I failed. 

 

I made a macro code to make two new variables using coalesce (based on numerics) and coalescec (based on characters). The following code actually worked.

 

%macro cluID_combined (n_id= , c_id= , order= );
	%let dim= %length(&order);

	%do i=1 %to &dim;
	%let no= %substr(&order, &i, 1);
	%if &i.= 1 %then %do;
		%let c_list= &c_id.&no;	
		%let n_list= &n_id.&no;	
		%end;
	%else %do;
		%let c_list= &c_list, &c_id.&no;
		%let n_list= &n_list, &n_id.&no;
		%end;
	%end;
	&c_id._&order. = coalescec(&c_list.);
	&n_id._&order. = coalesce(&n_list.);
%mend;

data tcult.set4; set tcult.set3;
%cluID_combined (n_id= ptnr_cluID, c_id= ptnr_clu, order= 153);
%cluID_combined (n_id= ptnr_cluID, c_id= ptnr_clu, order= 135);
run;

 

The below is what I got by MPRINT. 

%cluID_combined (n_id= ptnr_cluID, c_id= ptnr_clu, order= 153);
MPRINT(CLUID_COMBINED): ptnr_clu_153 = coalescec(ptnr_clu1, ptnr_clu5, ptnr_clu3);
MPRINT(CLUID_COMBINED): ptnr_cluID_153 = coalesce(ptnr_cluID1, ptnr_cluID5, ptnr_cluID3);
%cluID_combined (n_id= ptnr_cluID, c_id= ptnr_clu, order= 135);
MPRINT(CLUID_COMBINED): ptnr_clu_135 = coalescec(ptnr_clu1, ptnr_clu3, ptnr_clu5);
MPRINT(CLUID_COMBINED): ptnr_cluID_135 = coalesce(ptnr_cluID1, ptnr_cluID3, ptnr_cluID5);

 

Then, I modified the loop2 according to your suggestions (with UNQUOTE), and run the following code using loop2.

%macro loop2 (list=, statement=);
	%let N= %sysfunc(countw(&list));	
	%do x= 1 %to &N;
		%let xth_var= %scan(&list, &x);
		%unquote(&STATEMENT);
	%end;
%mend;

data tcult.set4; set tcult.set3;
%loop2 (list= 153 135, 
statement= %cluID_combined (n_id= ptnr_cluID, c_id= ptnr_clu, order= &xth_var. ); 
);
run;

Then I got the below error:

 

1156 data tcult.set4; set tcult.set3;
1157 %loop2 (list= 153 135,
1158 statement= %cluID_combined (n_id= ptnr_cluID, c_id= ptnr_clu, order= &xth_var. );
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
WARNING: Apparent symbolic reference XTH_VAR not resolved.
1159 );
NOTE: Line generated by the macro function "UNQUOTE".
1 ptnr_clu_153 = coalescec(ptnr_clu&, ptnr_clux, ptnr_clut, ptnr_cluh, ptnr_clu_,
-
---------
-
22
386
22

201

76

I've noticed that the issue is coming from order= &xth_var. in my code. but I don't know how to fix this...

 

I should've described my original issue from the beginning. But I'm really new to this community. Hope that you understand. Could you please let me know how to fix this issue?

 

 

 

34reqrwe
Quartz | Level 8

try using %nrstr like you were previously:

data tcult.set4; set tcult.set3;
%loop2 (list= 153 135, 
statement= %nrstr(%cluID_combined (n_id= ptnr_cluID, c_id= ptnr_clu, order= &xth_var. ); )
);
run;
braam
Quartz | Level 8

Oh thanks! That actually worked. In the end, do I have to %unquote and %nrstr together? It's a little hard to understand the logic behind, but thanks to all who helped me out.

 

gamotte
Rhodochrosite | Level 12

Hello,

 

Assuming you only want to loop on one argument for a given macro, you can create an intemediary

macro (like "prefix_var" in the example below) which fix the other arguments of the macro you want to loop on.

 

The macro loop2 is then expected to take as arguments the name of a single argument macro

and the list of possible values for this argument.

 

%macro loop2(macroname, arguments);

    %do i= 1 %to %sysfunc(countw(&arguments.));
        %&macroname(%scan(&arguments.,&i.));
    %end;

%mend;

%macro rename(var, prefix);
    
    data temp;
       set temp;
       rename &var.=&prefix.&var.;
    run;

%mend;

%macro prefix_var(var);

    %rename(&var.,test_);

%mend;

data temp;
set sashelp.class;
run;

%loop2(prefix_var, name sex age height weight);

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

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
  • 9 replies
  • 831 views
  • 0 likes
  • 6 in conversation