-1

I am trying to create variables from macro variables with increasing index in a SAS macro but I am getting missing values for variables aa_index and I am getting 0 values for bb_index which should not bethe case. Please help with how I can adjust my macro to work properly. My SAS macro is shown below;

    %macro cashflow_macro(index=,aa_1=,aa_2=,aa_3=,aa_4=,);
    /*create bb fields*/
    %put bb_1 = &aa_&index - &aa_(&index+1);
    %put bb_2 = &aa_(&index+1) - &aa_(&index+2);
    %put bb_3 = &aa_(&index+2) - &aa_(&index+3);

    /*create cc fields*/
    cc_1 = max(bb_1,0);
    cc_2 = max(bb_2,0);
    cc_3 = max(bb_3,0);
%mend;

data ccc;
%cashflow_macro(index=1,aa_1=400,aa_2=300,aa_3=250,aa_4=270);
run;
ccc
  • 189
  • 1
  • 3
  • 12
  • 1
    Please include an example of how you're calling the macro with the parameters specified, and in a data step I assume? – Reeza Aug 30 '21 at 17:18
  • For starters your `bb_##` references should be preceded with a & to indicate that they're macro variables. You also need `%eval` or `%sysevalf `to have your increments `(&index+8)`work correctly and I suspect you need to drop the brackets `()`. And assignments such as cc_24 don't make sense in open code so there are many issues with your code. Without knowing what you're trying to achieve I'm not sure where to start with fixes. And `%PUT` displays variables it does not create them. I think you need %LET instead. – Reeza Aug 30 '21 at 17:21
  • 1
    Create a simplified version of this with say just 4 aa_ variables, and show us the SAS code you want generated from the macro call. Right now this has a lot of problems, but because of those it's not clear what it should be. – Joe Aug 30 '21 at 19:40
  • Here is a simplified example where I create the macro then call it; %macro cashflow_macro(index=,aa_1=,aa_2=,aa_3=,aa_4=,); /*create bb fields*/ %put bb_1 = &aa_&index - &aa_(&index+1); %put bb_2 = &aa_(&index+1) - &aa_(&index+2); %put bb_3 = &aa_(&index+2) - &aa_(&index+3); /*create cc fields*/ cc_1 = max(bb_1,0); cc_2 = max(bb_2,0); cc_3 = max(bb_3,0); %mend; data ccc; %cashflow_macro(index=1,aa_1=400,aa_2=300,aa_3=250,aa_4=270); run; – ccc Aug 31 '21 at 06:41
  • Please show the SAS code (with NO macro variable references) you want generated by this call to the macro: `%cashflow_macro(index=1,aa_1=400,aa_2=300,aa_3=250,aa_4=270); ` – Tom Aug 31 '21 at 21:13

1 Answers1

0

Taking this mostly out of macros and into arrays which are much more efficient.

%macro cashflow_macro(index=,aa_1=,aa_2=,aa_3=,aa_4=,);

*create variable with index - 1 for other variables;
%let index1 = %eval(&index - 1);

 *declare arrays;
 array _aa (*) aa_1-aa_&index (
 %do i=1 %to &index;
     &&&aa_&i.
 %end;
    );
    
array _bb(*) bb_1 - bb_&index1;
array _cc(*) cc_1 - cc_&index1;

*calculations;
do i=1 to &index1;
_bb(i) = _aa(i) - _aa(i+1);
_cc(i) = max(_bb(i), 0);
end;




%mend;

data ccc;
 %cashflow_macro(index=4,aa_1=400,aa_2=300,aa_3=250,aa_4=270);
run;

And a possibly more simplified version:

%macro cashflow_macro_revised(series=);
   
    *create variable with index - 1 for other variables;
    %let index = %sysfunc(countw(&series));
    %let index1 = %eval(&index - 1);
    
     *declare arrays;
     array _aa (*) aa_1-aa_&index (&series);
        
    array _bb(*) bb_1 - bb_&index1;
    array _cc(*) cc_1 - cc_&index1;
    
    *calculations;
    do i=1 to &index1;
    _bb(i) = _aa(i) - _aa(i+1);
    _cc(i) = max(_bb(i), 0);
    end;




%mend;

data ccc;
     %cashflow_macro_revised(series=400 300 250 270);
run;

If you really want to stick with macros this will work but does generate some warnings. I don't have time to debug beyond this but it seems to work.

%macro cashflow_macro(index=4,aa_1=,aa_2=,aa_3=,aa_4=,);
   
    *create variable with index - 1 for other variables;
    %let index1 = %eval(&index - 1);
    

     %do i=1 %to &index1;
     
        %let bb_&i =  &&&aa_&i. - &&&aa_%eval(&i+1);
        bb_&i = &&&bb_&i.;
        cc_&i = max(&&&bb_&i, 0);
     %end;




%mend;



data ccc1;
%cashflow_macro(index=4,aa_1=400,aa_2=300,aa_3=250,aa_4=270);
run;

Reeza
  • 20,510
  • 4
  • 21
  • 38
  • 1
    Why do you need INDEX1 created? `do i=1 to &index - 1;` – Tom Aug 31 '21 at 21:09
  • If it gets used in multiple places I like to do the calculation only once. The indexes for the other arrays are also index-1. It's probably not needed in that last example. – Reeza Aug 31 '21 at 21:13