Contributor
Posts: 23

# writing a macro to compute results for three variables

I want to write a macro for the following piece of code:

data nd;
set nd;
if in2016=1 then do;
if road = 98 then air_a = 98; /*non*/
else if road = 2 then air_a = 0;
end;

if road = 1 then do;
if car_a in (10, 1) then bike_res_a = 0; /*withdrew or completed*/
end;

if car_a in (2,4) then do; * currently or deferred;
if bike_a = 1 then bike_res_a = 0; *year12;
else if bike_a in (2,3,4,5,6) then bike_res_a = bike_a - 1;
else if bike_a in (7,8,9,10) then bike_res_a = 6;
else if bike_a  =  11  then bike_res_a = 7;
else if bike_a  in (12 13) then bike_res_a = 8;
else if bike_a  =  14 then bike_res_a = 9;
else if bike_a  >= 15 then bike_res_a = 0;
end;

run;

I want this to run through three times. One where there is _a, one where there is _b and one where there is _c. So I want to run through a,b,c. Just wandering how to do this in a macro?

Super User
Posts: 23,323

## Re: writing a macro to compute results for three variables

You should use arrays not a macro here.

https://stats.idre.ucla.edu/sas/seminars/sas-arrays/

This paper has some good examples.

http://www2.sas.com/proceedings/sugi30/001-30.pdf

Super User
Posts: 9,923

## Re: writing a macro to compute results for three variables

Use array processing, as @Reeza already suggested.

And replace the if-then-else-if chain with a select block:

``````data nd;
set nd;
array bikes {3} bike_a bike_b bike_c;
array bikeres {3} bike_res_a bike_res_b bike_res_c;
if in2016=1 then do;
if road = 98 then air_a = 98; /*non*/
else if road = 2 then air_a = 0;
end;

if road = 1 then do;
if car_a in (10, 1) then bike_res_a = 0; /*withdrew or completed*/
end;

if car_a in (2,4) then do; * currently or deferred;
do i = 1 to 3;
select (bikes{i});
when (1) bike_res{i} = 0; *year12;
when (2,3,4,5,6) bike_res{i} = bikes{i} - 1;
when (7,8,9,10) bike_res{i} = 6;
when (11) bike_res{i} = 7;
when (12,13) bike_res{i} = 8;
when (14) bike_res{i} = 9;
otherwise bike_res{i} = 0;
end; * select;
end; * iterative do;
end;
drop i;
run;``````
---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
How to convert datasets to data steps
How to post code
Posts: 1,831

## Re: writing a macro to compute results for three variables

@KurtBremser, your code doesn't replace all   _a   variables as asked.   See lines:

/*-------------------------------------------------------------------------------------------------/

`if in2016=1 then do; `

`   if road = 98 then air_a = 98; /*non*/ `

`   else if road = 2 then air_a = 0; end;`

`if road = 1 then do; `

`   if car_a in (10, 1) then bike_res_a = 0; /*withdrew or completed*/ `

`end; `

`if car_a in (2,4) then do;`

/*-------------------------------------------------------------------------------------------------/

Therefore, I think it is easier to be done by a macro.

I too preffer the CASE instead IF-THEN-ELSE method.

So proposed code is:

``````%macro doit(suffix);
if in2016=1 then do;
if road = 98 then air&suffix. = 98; /*non*/
else if road = 2 then air&suffix. = 0;
end;

if road = 1 then do;
if car&suffix. in (10, 1) then bike_res&suffix. = 0; /*withdrew or completed*/
end;

if car&suffix. in (2,4) then do; * currently or deferred;
select (bikes&suffix.);
when (1) bike_res&suffix. = 0; *year12;
when (2,3,4,5,6) bike_res&suffix. = bikes&suffix. - 1;
when (7,8,9,10) bike_res&suffix. = 6;
when (11) bike_res&suffix. = 7;
when (12,13) bike_res&suffix. = 8;
when (14) bike_res&suffix. = 9;
otherwise bike_res&suffix. = 0;
end; * select;
end;
%mend doit;

data nd;
set nd;
%doit(_a);
%doit(_b);
%doit(_c);
run;
``````
Super User
Posts: 9,923

## Re: writing a macro to compute results for three variables

Yes, then the do loop needs to be moved out one level to cover all variables:

``````data nd;
set nd;
array airs {3} air_a air_b air_c;
array cars {3} car_a car_b car_c;
array bikes {3} bike_a bike_b bike_c;
array bikeres {3} bike_res_a bike_res_b bike_res_c;
do i = 1 to 3;
in2016 = 1 then do;
if road = 98 then airs{i} = 98; /*non*/
else if road = 2 then airs{i} = 0;
end;
if road = 1 then do;
if cars{i} in (10,1) then bikeres{i} = 0; /*withdrew or completed*/
end;
if car_a in (2,4) then do; * currently or deferred;
select (bikes{i});
when (1) bike_res{i} = 0; *year12;
when (2,3,4,5,6) bike_res{i} = bikes{i} - 1;
when (7,8,9,10) bike_res{i} = 6;
when (11) bike_res{i} = 7;
when (12,13) bike_res{i} = 8;
when (14) bike_res{i} = 9;
otherwise bike_res{i} = 0;
end; * select;
end;
end; * iterative do;
drop i;
run;``````
---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
How to convert datasets to data steps
How to post code
Super User
Posts: 7,938

## Re: writing a macro to compute results for three variables

Just use arrays.  Take your code and replace _a with (i) and add the array statements and a DO loop.

``````data nd;
set nd;
array air air_a air_b air_c ;
array car car_a car_b car_c ;
array bike bike_a bike_b bike_c ;
array bike_res bike_res_a bike_res_b bike_res_c;
do i=1 to dim(air);
if in2016=1 then do;
if road = 98 then air(i) = 98; /*non*/
else if road = 2 then air(i) = 0;
end;

if road = 1 then do;
if car(i) in (10, 1) then bike_res(i) = 0; /*withdrew or completed*/
end;

if car(i) in (2,4) then do; * currently or deferred;
if bike(i) = 1 then bike_res(i) = 0; *year12;
else if bike(i) in (2,3,4,5,6) then bike_res(i) = bike(i) - 1;
else if bike(i) in (7,8,9,10) then bike_res(i) = 6;
else if bike(i)  =  11  then bike_res(i) = 7;
else if bike(i)  in (12 13) then bike_res(i) = 8;
else if bike(i)  =  14 then bike_res(i) = 9;
else if bike(i)  >= 15 then bike_res(i) = 0;
end;
end;
run;``````
Discussion stats
• 5 replies
• 153 views
• 0 likes
• 5 in conversation