Macro Array v2

From sasCommunity
Jump to: navigation, search

sugi.29.2004 Array: Construction and Usage of Arrays of Macro Variables

Author: Ronald_J._Fehd

Programs

Macro Array, v2

/*   macro: Array returns a series of macro-variables
            named &Name.1 &Name.2 .. &Name.N
            and a macro-variable named Dim_&Name.
            i.e. %Array(Var,Q04A Q04B Q04C);
            returns: Var1::Q04A Var2::Q04B Var3::Q04C, Dim_Var::3
Parameters: array-name
            array-elements: either of
            horizontal list of array element values
            vertical list: data set, variable
Notes     : must declare %local macro variables Dim_Array-Name
            and Array-Name1 ... Array-NameN -before- calling Array
            length(Array-Name) must be <= 28
            length(Array-Name) + length(dim_Array-Name) must be <= 32
Usage     : within macro: see also test data
            %Array(Array-Name,Item-List); run;
            %Array(Array-Name,data=Data-Name,var=Var-Name); run;
Usage     : in open code:
            %Array(Array-Name,data=Data-Name,var=Var-Name,_global_=1);
            run;
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
            %Qscan symput SysPbuff %until SQL 
Author    : Ronald J. Fehd 2004
Source    : http://www2.sas.com/proceedings/sugi29/070-29.pdf 
            Array: Construction and Usage of Arrays of Macro Variables*/
 
%Macro Array 
(Name        /*macro-var array-name: len(array-name) must be <= 28 */
,List        /*horizontal list of array-elements */
,Libname  = WORK/*vertical list: libref */
,Data     = . /*vertical list: data set name */
,Var      = . /*vertical list: variable in data set */
,Dim      = 9 /*vertical list: how many _global_ vars to allocate? */
,Where    = 1 /*vertical list: subset phrase use w/DICTIONARY.tables*/
,Delimitr = %str( ).<%str(()]&!$*%str())ˆ-/%>\/*horiz-list delimiter */
,_Global_ = 0 /*?make mac-vars %global?, **
,I        = 1 /*local macro loop counter/index */
,Item     = . /*local temp var for Qscan */
,Print    = noprint  /*local: to see SQL select use ,PRINT=) */
,MaxLenMvarName = 28 /*local max length mVar Name */
)/des = 'create array of mac-vars from list/data' /* */
parmbuff /* ParmBuff: see SysPbuff */
;/* .................................... ............................ */
%If     "&Name." ne ""                  
    and "&List." ne "" and %length(&Name.) le &MaxLenMvarName.
    %then %do; 
    %*case.1: Name & List;
    %Let I = 1;
    %Let Item = %Qscan(&List,&I,&Delimitr);
    %Do %until(&Item. = );
        %If &_Global_ %then %do; %global &Name.&I; %end;
        %Let &Name.&I = &Item.;
        %Let I = %eval(&I + 1);
        %Let Item = %Qscan(&List,&I,&Delimitr);
        %*do %until; 
        %end;
    %If &_Global_ %then %do; %global Dim_&Name.; %end;
    %Let Dim_&Name. = %eval(&I - 1);
    %Put @@Array returns &Name., dim=&&Dim_&Name. list<&List.>;
    %*case.1;
    %end;
 
%Else %If "&Name." ne ""                
    and "&List." eq "" and "&Data." ne "."
    and "&Var." ne "." and %length(&Name.) le &MaxLenMvarName.
    %then %do;
    %*case.2: Name & (Data & Var);
    %If &_Global_. %then %do; 
        %Global Dim_&Name.;
        %Let Dim_&Name. = &Dim.;
        %Do I = 1 %to &&Dim_&Name.; 
            %Global &Name.&I.; 
            %end;
        %*If _Global_; 
        %end;
    proc SQL &Print.;
             select &Var.
             into :&Name.1 - :&Name.&SysMaxLong
             from &Libname..&Data.
             where &Where.;
             quit;
    %Let Dim_&Name. = &SqlObs.;
    %Put @@Array returns &Name. dim=&&Dim_&Name. &Data..&Var.; 
    %*case.2;
    %end;
 
%Else %Do; 
    %*case.3: 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(Array-Name,Item-List);
    %Put data+var: Array(Array-Name,Data=Data-Name,Var=Var-Name);
    %If %length(&Name.) gt &MaxLenMvarName. %then
        %Put length(Array-Name) must be <= &MaxLenMvarName.;
    %Put parmlist: <&SysPbuff.>;%* /ParmBuff macro statement option*;
    %Put parm: Array-Name = <&Name.> length = <%Length(&Name.)>;
    %Put parm: ItemList = <&List.>;
    %Put parm: Libname = <&LibName.> ;
    %Put parm: Data = <&Data.> ;
    %Put parm: Var = <&Var.> ;
    %Put parm: _Global_ = <&_Global_.> in (0,1); 
    %*case.3; 
    %end;
    %* ..................................... ................. Array; 
%Mend;

Test Data

/*-test data ----------- enable by ending this line with slash (/) **/
DATA VQ04; *convention for macro CheckAll setup;
     length Name $ 8; 
     *can use PROC Contents output data set;
Name = 'Q04A'; 
output;
Name = 'Q04B'; 
output;
Name = 'Q04C'; 
output; 
run;
 
%Macro Demo(Test=0,Dim_Var=10);%*initialize: declare macro array names;
%Do I = 1 %to &Dim_Var.; 
    %local Var&I.; 
    %end;
%If   &Test. eq 1 %then %do;
      %Array(Var,Q03A Q03B Q03C Q03D); 
      %end;
%Else %If &Test. eq 2 %then %do;
      %Array(Var
            ,data = VQ04
            ,var  = Name); 
      %end;
%Else %If &Test. eq 3 %then %do;
      %Array(Var
            ,Libname = Dictionary
            ,Data = Tables
            ,Var  = MemName
            ,Where = LibName eq 'WORK'
            ); 
      %end;
%Else %GoTo EXIT;
run;
%*illustrate usage in loop;
%Do I = 1 %to &Dim_Var.; 
    %Put Var&I. :: &&Var&I.; 
    %end;
%EXIT: run;
%* .......................... ................ Demo *; 
%Mend;
%Demo(Test = 1);
%Demo(Test = 2);
%Demo(Test = 3);
%Array(This_Mvar_Name_Is_Tooooo_Long,A B C D E);*see error msg;
%Array(Test,A B C D E,_Global_=1);*make mac-vars %global in open code;
%Put _User_;*show global list of macro-variables;
run; /* ................................ ............... Test Data end*/

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