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

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

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