0
votes

I am quite new with writing macros and I have a sas data step that seems to be repetitive. Is it possible to put this code in a sas macro that loops around the array so it is not repetitively written?

data vintage;
set data_have;


array amt {4} mob0-mob3;

if dist = 0 then do;
 do i = 1 to 4;
  amt{i} = dollar_value;
 end;
end;

if dist = 1 then do;
 do i = 2 to 4;
  amt{i} = dollar_val;
 end;
end;

if dist = 2 then do;
 do i = 3 to 4;
  amt{i} = dollar_val;
 end;
end;

if dist = 3 then do;
 do i = 4 to 4;
  amt{i} = dollar_val;
 end;
end;

run;

I have tried to write the following macro but unfortunately, it doesn't work.

%macro vx (datain, n, var, wo);

data vin;
set &datain;

array amt {4} mob0-mob3;

%let m = %eval(1+i);

%do i=1 %to &n;
 %if dist = i %then %do;
  %do j=2 %to m;
   mob&j = dollar_val;
  %end;
%end;


run;
%mend vx;

Thank you for any help.

1
I don't see where macro plays into this. You can replace your multiple loops with one do loop. do i=1+dist to 4; - Tom
You need show some example input and output data. - Tom
You're combining macro with non-macro in a way that doesn't make sense. - Joe

1 Answers

1
votes

First, this isn't something you need the macro language to solve; see Tom's comments. But I'll answer how to do it in the macro language anyway, since it is possible, and may help your learning.

Think of the macro language as a code-writer: like a junior programmer that you tell what you want SAS to do, and they do it for you. They're not SAS, they're writing SAS, and importantly they can't use the details of the dataset themselves: they can only use what's known about the dataset before it's opened (variable names are fine, but not the data in the variables) unless they write some code to find out what is in the dataset separately.

What you're doing is writing this a lot:

if dist = 0 then do;
 do i = 1 to 4;
  amt{i} = dollar_value;
 end;
end;

But with 0 and 1 varying. Right? So let's make them macro variables (rather, one macro variable).

if dist = &mv. then do;
 do i = &mv.+1 to 4;
  amt{i} = dollar_value;
 end;
end;

Notice I don't use &i. here, because that would be confusing. Instead I'll use something different, &mv..

Then, we need to make sure the if and do here are the right kinds. %do says "write this code many times". do on the other hand is for normal SAS do loops, and same in both cases for %if.

So here, we want to write this block of code many times, so %do the whole block; but inside the block, when we want to say if dist=... that is regular if (it's looking at the data value), and when we want to say do i = ... to 4 it is again regular do (it's regular SAS do loop, again dependent on data).

So here we go:

%macro vx (datain, n, var, wo);

data vin;
  set &datain;
  array mob[&n.]; *do not have to list them, it is by default;
  %do mv=1 %to &n;
    if dist = &mv then do;   *not MACRO if but regular if;
     do i = (&mv.+1) to m;  *not MACRO loop but regular loop;
       mob[i] = dollar_val;
     end;
    end;
  %end;
run;
%mend vx;

Now again, this is better done without macro.

data vin;
  set &datain.;
  array amt[4];
  if dist < 4 then do;
    do i = (dist+1) to 4;
      amt[i] = dollar_value;
    end;
  end;
run;

But it's certainly doable either way.