BookmarkSubscribeRSS Feed
ginak
Quartz | Level 8

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;

 

 

 

5 REPLIES 5
Astounding
PROC Star

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;

 

 

DanielLangley
Quartz | Level 8

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));
ballardw
Super User

@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.

 

DanielLangley
Quartz | Level 8

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
Tom
Super User Tom
Super User

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;

 

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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
  • 5 replies
  • 4862 views
  • 1 like
  • 5 in conversation