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?
You should use arrays not a macro here.
https://stats.idre.ucla.edu/sas/seminars/sas-arrays/
Additionally you can consider using a format instead of IF/THEN statements.
This paper has some good examples.
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;
@Kurt_Bremser, 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;
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;
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;
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.
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.