DATA Step, Macro, Functions and more

Looping through list of different numbers in Macro

Reply
Contributor
Posts: 71

Looping through list of different numbers in Macro

[ Edited ]

Hi all,

 

I apologize if this has been answered elsewhere. I tried to search for it on the boards but couldn't find the exact answer.

 

I have a list of, say, 10 variables.

I want to run a macro on the first 3 variables and the 7th, 8th and 9th variables. How would I go about indicating this? Let't just keep it to something simple like Proc Freq only for the sake of this example (but I end up manipulating the output and doing other things with it, and then doing other things with the other variables). The problem is that I usually know to say something like "%do i = 6 %to 9'"

but in this case, here I want to say "%do i = 1 %to 3, and i = 7 %to 9;"

 

The reason I'm doing this  is because I'll run the same commands on those sets of variables, and manipulate them the same way. And then I'll manipulate the output of the other frequencies a different way. The only other alternative I can think of is grouping said variables together in a list and running a loop on that group only, a different loop on a different group, etc.

 

 

 

%let list = q1
q2
q3
q4
q5
q6
q7
q8
q9
q10;

%macro q9freq;
     %do IncMiss = 1 %to 2  /*We want to run this all including missing, and not including missing*/

/***********************please check here***********************************/ %do 1 %to 3, 7 %to 9; /*This doesn't work, but I don't know how to fix it*/
/****************************************************************************/ %let var = %scan(&list, %eval(&i)); proc freq data = irblabel_1; tables &var/ list %if &IncMiss = 1 %then missing ; /*this semi colon closes the %if statement*/ ; /*This semicolon closes the tables statement*/ ods output Freq.Table1.OneWayFreqs = Freq&var.A&IncMiss; run; data freq&var.b&IncMiss (keep = Vname Answer PercentN); length Vname $256; format Vname $256.; retain Vname F_&var PercentN; set freq&var.A&IncMiss; where index(F_&var, "Yes") > 0 or index(F_&var, "Not") > 0 or index(F_&var, "Missing") > 0; Vname = scan(table, 2, " "); PercentN = round(percent,0.1); Answer = f_&var;/* Get the first word, blank delimited */ run; data Q9100&IncMiss; retain vname label length label $256; length vname $256; length answer $256; format label $256.; format vname $256.; format answer $256.; set blankq9 freqq1b&IncMiss freqq2b&IncMiss freqq3b&IncMiss freqq7b&IncMiss freqq8b&IncMiss freqq9b&IncMiss ; %MACRO LABELQ9(OLD, NEW); if Vname = &OLD then label = &new; %mend; %LABELQ9(" ", "label1:"); %LABELQ9("q1", "label2"); %LABELQ9("q2", "blah blah?"); %end; /*End loop going thru Q9-12*/ %end; /*End loop going thru missing and nonmissing*/ %mend; %q9freq;

 

 

 

Super User
Posts: 6,637

Re: Looping through list of different numbers in Macro

As you have seen, macro language doesn't support all the forms of a %DO statement that exist in a DATA step.

 

For this particular example, I would recommend just using two loops.  Package your complex code into a separate macro, and just use:

 

%do i=1 %to 3;

   %complex_code (&i)

%end;

%do i=7 %to 9;

   %complex_code (&i)

%end;

 

 

Occasional Contributor
Posts: 10

Re: Looping through list of different numbers in Macro

Hello. I do not have much experience with Macros but would a macro version of the below code do what you wish.

 

DATA Test;
DO i = 1 to 6;
	IF i le 3 then j = i; else j = (i-4)+7; *(Alternatively j = i + 3);
	OUTPUT;
END;
RUN;

It gives outputs that look like this

i -- j

1--1

2--2

3--3

4--7

5--8

6--9

 

And then

%let var = %scan(&list, %eval(&j));
Super User
Posts: 13,338

Re: Looping through list of different numbers in Macro

Posted in reply to DanielLangley

@DanielLangley wrote:

Hello. I do not have much experience with Macros but would a macro version of the below code do what you wish.

 

DATA Test;
DO i = 1 to 6;
	IF i le 3 then j = i; else j = (i-4)+7; *(Alternatively j = i + 3);
	OUTPUT;
END;
RUN;

It gives outputs that look like this

i -- j

1--1

2--2

3--3

4--7

5--8

6--9

 

And then

%let var = %scan(&list, %eval(&j));

Something like this?:

%macro dummy;
%DO i = 1 %to 6;
   %IF &i. le 3 %then %let j = &i.; 
   %else %let j =  %eval(&i. + 3);
   %put i=&i. j=&j;
%END;
%mend;

%dummy;

Since I put the %eval in the %else bit then you wouldn't need to use %eval in the %scan call.

 

Occasional Contributor
Posts: 10

Re: Looping through list of different numbers in Macro

Thanks. Yes. So the final code could look something like

 

%let list = q1
q2
q3
q4
q5
q6
q7
q8
q9
q10;

%macro q9freq;
	%DO IncMiss=1 %to 2; *this needed a semicolon here;
        %DO i=1 %to 6;
			%IF &i. le 3 %then %let j = &i.;
			%else %let j =  %eval(&i. + 3);
			%let var = %scan(&list, &j);
	
			/*Insert Complex Code here*/

		%end; *End loop going thru 1,2,3,7,8,9*;
	%end; *End loop going thru missing and nonmissing;
%mend;

%q9freq;

which iterates as

 

i=1 j=1 var=q1 IncMiss=1
i=2 j=2 var=q2 IncMiss=1
i=3 j=3 var=q3 IncMiss=1
i=4 j=7 var=q7 IncMiss=1
i=5 j=8 var=q8 IncMiss=1
i=6 j=9 var=q9 IncMiss=1
i=1 j=1 var=q1 IncMiss=2
i=2 j=2 var=q2 IncMiss=2
i=3 j=3 var=q3 IncMiss=2
i=4 j=7 var=q7 IncMiss=2
i=5 j=8 var=q8 IncMiss=2
i=6 j=9 var=q9 IncMiss=2
Super User
Super User
Posts: 7,936

Re: Looping through list of different numbers in Macro

The same way you would iterate over any set of non-numeric values.

%do i=1 %to %sysfunc(countw(&list));
  %let next=%scan(&list,&i);
  ....
%end;

If it is too hard for you to generate the space delimited list you could take advantage of the power of the data step to generate it.

For example you might do something like

data _null_;
  length list $200 ;
  do i=1 to 3,7 to 9 ;
    list=catx(' ',list,cats('q',i));
  end;
  call symputx('list',list);
run;

 

Ask a Question
Discussion stats
  • 5 replies
  • 118 views
  • 1 like
  • 5 in conversation