BookmarkSubscribeRSS Feed
BenBrady
Obsidian | Level 7

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?

5 REPLIES 5
Reeza
Super User

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. 

 

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

Kurt_Bremser
Super User

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;
Shmuel
Garnet | Level 18

@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;    
Kurt_Bremser
Super User

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

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;

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
  • 738 views
  • 0 likes
  • 5 in conversation