Macro Array v1

From sasCommunity
Jump to: navigation, search

sugi.22.1997 %ARRAY: construction and usage of arrays of macro variables

Author: Ronald_J._Fehd

successors:

  • Macro Array v2, uses SQL:

Array: Construction and Usage of Arrays of Macro Variables

Programs

Array.sas

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* MACRO: ARRAY
* PARAMETERS:
* array-name
* array-element values: either of
* horizontal list of array element values
* delimiters may be specified, see default list
* vertical list: data set w/ variable containing array values
* USAGE: 1. %_ARRAY(ARAYNAME,ITEM-LIST);
*        2. %_ARRAY(ARAYNAME,ITEM-LIST,DELIMITR=/);
*        3. %_ARRAY(ARAYNAME,DATA=DATANAME,VAR=Var-Name);
* DESCRIPTION:
* This macro returns a series of global macro-variables
* named &ARAYNAME.1 &ARAYNAME.2 .. &ARAYNAME.n
* and a macro-variable named DIM_&ARAYNAME.
* i.e. %ARRAY(VAR,Q04A Q04B Q04C);
* returns: VAR1::Q04A VAR2::Q04B VAR3::Q04C, DIM_VAR::3
* NOTES:
* length(ARAYNAME) must be <= 4
* length(ARAYNAME) + length(dim_ARAYNAME) must be <= 8
* CAUTION: creates %GLOBAL macro-variables
* PROCESS: case 1: scan user-provided list of array-elements
*          case 2: data set: call symput of variable
*          case 3: error msg
* KEYWORDS: array %ARRAY CONTENTS delimiter loop macro PARMBUFF %scan
*           symput SYSPBUFF %until */
 
%MACRO ARRAY(/* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 ARAYNAME /*macro-var array-name: len(array-name) must be <= 4 */
,ITEMLIST /*horizontal list of array-element values */
,DATA =. /*vertical list: data set name */
,VAR =. /*vertical list: variable in data set */
,DELIMITR=%STR( ).<%str(()]&!$*%str())^-/%>\
         /*delimiter of horiz-list */
)/PARMBUFF;
  /* see SYSPBUFF usage in error msg -*/
/*- case 1: ARAYNAME & ITEMLIST */
%IF "&ARAYNAME" ne ""                 
    and "&ITEMLIST" ne "" 
    and %length(&ARAYNAME) le 4 %THEN %DO;
 
    %local I ITEM;
    %LET I = 1;
    %LET ITEM = %qscan(&ITEMLIST,&I.,&DELIMITR);
    %DO %until(&ITEM = );
        %global &ARAYNAME.&I;
        %LET &ARAYNAME.&I = &ITEM.;
        %LET I = %eval(&I + 1);
        %LET ITEM = %qscan(&ITEMLIST,&I.,&DELIMITR);
        /* %DO %until*/
        %END;
    %global DIM_&ARAYNAME;
    %LET DIM_&ARAYNAME = %eval(&I - 1);
    %PUT macro proc ARRAY returns array: &ARAYNAME, dim=&&DIM_&ARAYNAME;
    %PUT from list <&ITEMLIST.>;
    /* case.1 ARAYNAME & ITEMLIST */ 
    %END;
 
/* case 2: ARAYNAME & (DATA & VAR) */
%ELSE %IF "&ARAYNAME" ne ""        
      and "&ITEMLIST" eq "" and "&DATA" ne "." and "&VAR" ne "."
      and %length(&ARAYNAME) le 4 %THEN %DO;
 
proc CONTENTS data = &DATA (keep = &VAR.) noprint
              out  = CONTENTS(keep = Nobs Type);
%global DIM_&ARAYNAME;
DATA _NULL_;
     length VarType $ 1;
set CONTENTS;
if Type = 1 then VarType = 'N';
else VarType = 'C';
call symput("VARTYPE" ,VarType);
call symput("DIM_&ARAYNAME",trim(left(put(Nobs,32.))));
stop;
run;
 
%local I;
%DO I = 1 %TO &&DIM_&ARAYNAME.;
    %global &ARAYNAME.&I.;
    %END;
 
DATA _NULL_;
retain I 0;
do until(EndoFile);
   set &DATA. end = EndoFile;
   I + 1;
   /* symput(mac-var name : prefix + suffix,
           mac-var value: variable name */
   call symput("&ARAYNAME" !! left(put(I , 7.0 ) )
              ,trim(left(
        %IF "&VARTYPE" = "N" %THEN put(&VAR,best32.16) ;
        %ELSE &VAR ;
        /*symput closure*/
        )));
   /*do until(EndoFile)*/
   end;
stop;
run;
 
%PUT macro proc ARRAY returns array: &ARAYNAME, dim=&&DIM_&ARAYNAME.;
%PUT from data = &DATA, var = &VAR.;
/*case.2 ARAYNAME & (DATA & VAR)*/
%END;
 
%ELSE %DO;
      /* print error msg -*/
      %PUT ERROR: in macro ARRAY:;
      %PUT array-name : required;
      %PUT array-elements may be list, or (data and var);
      %PUT list : ARRAY(ARAYNAME,ITEM-LIST);
      %PUT data+var: ARRAY(ARAYNAME,DATA=DATA-NAME,VAR=VAR-NAME);
      %IF %length(&ARAYNAME) gt 4 %THEN
          %PUT length(ARAYNAME) must be <= 4;
      %PUT parmlist: <&SYSPBUFF.>;
           /*from /PARMBUFF macro statement option*/
      %PUT parm: ARAYNAME = <&ARAYNAME.> length = <%length(&ARAYNAME)>;
      %PUT parm: ITEMLIST = <&ITEMLIST.>;
      %PUT parm: DATA = <&DATA.> ;
      %PUT parm: VAR = <&VAR.> ;/*.............. ANY ERRORS*/
      %END;
/*..................................................... ARRAY */
%MEND;

Test Data

/*-test data - enable by ending this line with slash (/) **/
DATA VQ04;
*convention for %CHECKALL setup;
length Name $ 8;
*can use proc CONTENTS output data set;
Name = .Q04A.;
output;
Name = .Q04B.;
output;
Name = .Q04C.;
output;
run;
 
%MACRO DEMO(DATA_OUT,ITEMLIST);
* typical usage -*;
%IF &ITEMLIST ne %THEN %ARRAY(VAR, &ITEMLIST.);
%ELSE %ARRAY(VAR, DATA = V&DATA_OUT., VAR = Name);
%DO I = 1 %TO &DIM_VAR.;
    %PUT VAR&I. :: &&VAR&I.;
    %END;
*....................................................... DEMO *;
%MEND;
%DEMO(Q03, Q03A Q03B Q03C);
 
*data exploration usage;
%DEMO(Q04);
*production usage;
%ARRAY(TOOBIG,A B C D E);
*see error msg;
%PUT _user_;*show list of macro-variables;
RUN;
/*................................................. END TEST DATA*/


--Ronald_J._Fehd macro.maven == the radical programmer 07:35, 12 June 2012 (EDT)