0
votes

I'm trying to write robust code to assign values to macro variables. I want the names of the macro variables to depend on values coming from the variable 'subgroup'. So subgroup could equal 1, 2, or 45 etc. and thus have macro variable names trta_1, trta_2, trt_45 etc.

Where I am having difficulty is calling the macro variable name. So instead of calling e.g. &trta_1 I want to call &trta_%SCAN(&subgroups, &k), which resolves to trta_1 on the first iteration. I've used a %SCAN function in the macro variable name, which is throwing up a warning 'WARNING: Apparent symbolic reference TRTA_ not resolved.'. However, the macro variables have been created with values assigned.

How can I resolve the warning? Is there a function I could run with the %SCAN function to get this to work?

data data1 ;
  input subgroup trta trtb ;
  datalines ;
  1 30 58
  2 120 450
  3 670 3
run;

%LET subgroups = 1 2 3 ;
%PUT &subgroups;

%MACRO test;
  %DO k=1 %TO 3;

    DATA test_&k;
      SET data1; 
      WHERE subgroup = %SCAN(&subgroups, &k);
      CALL SYMPUTX("TRTA_%SCAN(&subgroups, &k)", trta, 'G');
      CALL SYMPUTX("TRTB_%SCAN(&subgroups, &k)", trtb, 'G'); 
    RUN;  

    %PUT "&TRTA_%SCAN(&subgroups, &k)" "&TRTB_%SCAN(&subgroups, &k)"; 
  %END;

%MEND test;
%test;
2
You've used &subgroups in your macro but &subtest outside?DTS
@dennis suter Ah yes, I was testing it and forgot to change it back, thanks! It's updated now.Dawnoak

2 Answers

1
votes

Using the structure you've provided the following will achieve the result you're looking for.

data data1;
  input subgroup trta trtb;
  datalines;
1 30 58
2 120 450
3 670 3
;
run;

%LET SUBGROUPS = 1 2 3;
%PUT &SUBGROUPS;

%MACRO TEST;
  %DO K=1 %TO 3;

    %LET X = %SCAN(&SUBGROUPS, &K) ;

    data test_&k;
      set data1; 
      where subgroup = &X ;
      call symputx(cats("TRTA_",&X), trta, 'g');
      call symputx(cats("TRTB_",&X), trtb, 'g'); 
    run;  

    %PUT "&&TRTA_&X" "&&TRTB_&X"; 
  %END;
%MEND TEST;
%TEST;

However, I'm not sure this approach is particularly robust. If your list of subgroups changes you'd need to change the 'K' loop manually, you can determine the upper bound of the loop by dynamically counting the 'elements' in your subgroup list.

If you want to call the macro variables you've created later in your code, you could a similar method.

data data2;
  input subgroup value;
  datalines;
1  20
2  25
3  15
45 30
  ;
run ;


%MACRO TEST2;
  %DO K=1 %TO 3;

    %LET X = %SCAN(&SUBGROUPS, &K) ;

    data data2 ;
      set data2 ;
      if subgroup = &X then percent = value/&&TRTB_&X  ;
      format percent percent9.2 ;      
    run ;
  %END;
%MEND TEST2;

%TEST2 ;

Effectively, you're re-writing data2 on each iteration of the loop.

0
votes

This should cover your requirements. You can load and unload an array of macro variable without a macro. I have included an alternate method of unloading a macro variable array with a macro for comparison.

Load values into macro variables including Subgroup number within macro variable name e.g. TRTA_45.

data data1;
    input subgroup trta trtb;

    call symput ('TRTA_'||compress (subgroup), trta);
    call symput ('TRTB_'||compress (subgroup), trtb);

    datalines;
    1 30 58
    2 120 450
    3 670 3
    45 999 111
    ;
run;

No need for macro to load or refer to macro variables.

%put TRTA_45: &TRTA_45.;

%let Subgroup_num = 45;

%put TRTB__&subgroup_num.: &&TRTB_&subgroup_num.;

If you need to loop through the macro variables then you can use Proc SQL to generate a list of subgroups.

proc sql noprint;
select  subgroup
,   count (*)   
into    :subgroups separated by ' '
,   :No_Subgroups
from    data1
;
quit;

%put Subgroups: &subgroups.;

%put No_Subgroups: &No_Subgroups.;

Use a macro to loop through the macro variable array and populate a table.

%macro subgroups;

data subgroup_data_macro;

%do i = 1 %to &no_subgroups.;
    %PUT TRTA_%SCAN(&subgroups, &i ): %cmpres(&TRTA_%SCAN(&subgroups, &i ));
    %PUT TRTB_%SCAN(&subgroups, &i ): %cmpres(&TRTB_%SCAN(&subgroups, &i ));

    subgroup = %SCAN(&subgroups, &i );

    TRTA    = %cmpres(&TRTA_%SCAN(&subgroups, &i ));
    TRTB    = %cmpres(&TRTB_%SCAN(&subgroups, &i ));    

    output;
%end;
run;
%mend subgroups;

%subgroups;

Or use a data step (outside a macro) to loop through the macro variable array and populate a table.

data subgroup_data_sans_macro;

do i = 1 to &no_subgroups.;
    subgroup = SCAN("&subgroups", i );

    TRTA = input (symget (compress ('TRTA_'||subgroup)),20.);
    TRTB = input (symget (compress ('TRTB_'||subgroup)),20.);

    output; 
end;
run;    

Ensure both methods (within and without a macro) produce the same result.

proc compare 
base = subgroup_data_sans_macro
compare = subgroup_data_macro
;
run;