Search notes:

SAS macros for array processing

array.sas

%macro tq84_array(values, delim=%str( ));
/*
    After an idea outlined in
      ARRAY.sas   (https://github.com/Jiangtang/SAS_ListProcessing/blob/master/ARRAY.sas)
    by
      Ted Clay  , M.S.   tclay@ashlandhome.net  (541) 482-6435
      David Katz, M.S.   www.davidkatzconsulting.com
     "Please keep, use and pass on the ARRAY and DO_OVER macros with
      this authorship note.  -Thanks "
*/

   %local array_name;
   %let   array_name = %tq84_createId(tq84_array_);

   %local elem_val i;
   %let   elem_val = qqqqqqqqqq;
   %let   i        = 1;
   %let   elem_val = %scan(%str(&values), &i, %str(&delim));

   %do %while (&elem_val ne %str());
       %global &array_name&i;
       
       %let    &array_name&i=&elem_val;

       %let i       = %eval(&i + 1);
       %let elem_val= %scan(%str(&values), &i, %str(&delim));

  %end;

  %global &array_name.s;
  %let    &array_name.s = %eval(&i-1);

  &array_name

%mend tq84_array;



%macro tq84_arrayLength(array);
       &&&array.s
%mend  tq84_arrayLength;


%macro tq84_arraySetVal(array, pos, val);

   %local len;
   %let   len = %tq84_arrayLength(&array);

   %if &len < &pos %then %do;
       %put tq84_arraySetVal: array &array: pos = &pos, but length only &len;
       %abort;
   %end; %else %do;
        %global &array&pos;
        %let    &array&pos=&val;
   %end;

%mend  tq84_arraySetVal;


%macro tq84_arrayGetVal(array, pos);

   %local len;
   %let   len = %tq84_arrayLength(&array);

   %if &len < &pos %then %do;
       %put tq84_arraySetVal: array &array: pos = &pos, but length only &len;
       %abort;
   %end; %else %do;
        %global &array&pos;
        &&&array&pos
   %end;

%mend  tq84_arrayGetVal;


%macro tq84_arrayPushBack(array, val);

   %local len;
   %let   len = %tq84_arrayLength(&array);

   %let   len = %eval(&len+1);

   %let    &array.s=&len;
   %tq84_arraySetVal(&array, &len, &val)

%mend  tq84_arrayPushBack;


%macro tq84_arrayApply(array, funcref);
    
    %local macroName;
    %let   macroName = %tq84_createMacro_M(&funcref, this);

    %local i;
    %do i = 1 %to &&&array.s;
        %&macroName(&&&array.&i)
    %end;

%mend  tq84_arrayApply;


%macro tq84_arrayMap(array, funcref);
 
  %local macroNameAM;
  %let   macroNameAM = %tq84_createMacro_M(&funcref, this);
  
  %local ret;
  %let   ret = %tq84_array();

  %tq84_arrayApply(&array, %nrstr(
       %put this = &this;

       %local evaluated;
       %let   evaluated = %&macroNameAM(&this);

       %tq84_arrayPushBack(&ret, &evaluated)
  ))

  &ret

%mend  tq84_arrayMap;


%macro tq84_arrayJoin(array, delim=%str( ));
   
   %local ret;
   %local i;

   %do i = 1 %to %tq84_arrayLength(&array);

      %if &i > 1                         %then %do;
          %let ret = &ret&delim;
      %end;

      %let ret = &ret%tq84_arrayGetVal(&array, &i);

   %end;
  
   &ret

%mend tq84_arrayJoin;
Github repository about-SAS, path: /macros/array.sas

Tests

Size/length of array

%let foo_bar_baz = %tq84_array(foo bar baz);

%put size of foo_bar_baz is %tq84_arrayLength(&foo_bar_baz); /* size of foo_bar_baz is 3 */
Github repository about-SAS, path: /macros/tests/array/length.sas

Get value of an element in array

%let oneTwoThreeEtc = %tq84_array(one two three four five six seven eight nine ten);

%put Element 5 in oneTwoThreeEtc is %tq84_arrayGetVal(&oneTwoThreeEtc, 5); /* Element 5 in oneTwoThreeEtc is five  */
%put Element 8 in oneTwoThreeEtc is %tq84_arrayGetVal(&oneTwoThreeEtc, 8); /* Element 8 in oneTwoThreeEtc is eight */
Github repository about-SAS, path: /macros/tests/array/getVal.sas

Iterating over elements in array

%tq84_arrayApply is modelled after the apply function in JavaScript.
The first argument is the (name of the) array, the second argument a string from which a macro is compiled (using createMacro). Within this macro, the macro variable &this contains the value of the element.
%let oneThroughFive = %tq84_array(one two three four five);
%tq84_arrayApply(&oneThroughFive, %nrstr(
  %put this = &this;
))
/*
this = one
this = two
this = three
this = four
this = five
*/
Github repository about-SAS, path: /macros/tests/array/apply.sas

Modifying the value of elements in the array

%tq84_arraySetVal(&array, &elem, &newValue set the value of an element in the array.
%let oneThroughFive = %tq84_array(one two three four five);

%tq84_arraySetVal(&oneThroughFive, 1, ONE in UPPERCASE)
%tq84_arraySetVal(&oneThroughFive, 4, IV)

%tq84_arrayApply(&oneThroughFive, %nrstr(
   %put this = &this;
))
/*
this = ONE in UPPERCASE
this = two
this = three
this = IV
this = five
*/
Github repository about-SAS, path: /macros/tests/array/setVal.sas

Adding elements to the array

%tq84_arrayPushBack(&array, &val) adds an element to the array.
%let fooBarBaz = %tq84_array(foo bar baz);

%tq84_arrayPushBack(&fooBarBaz, more)

%put size of fooBarBaz is %tq84_arrayLength(&fooBarBaz);
/*
   size of fooBarBaz is 4
*/

%tq84_arrayApply(&fooBarBaz, %nrstr(
   %put this = &this;
))
/*
   this = foo
   this = bar
   this = baz
   this = more
*/

Joining elements to a string

The values/elements of an array can be joined to create a string.
By default, the elements are joined by a single space; the delim option can be used to change that.

Evaluating an expression for each element in the array

With %tq84_arrayMap, an expression is evaluated for each element in the array. From the values of these expressions, a new array is returned.
%let abc_def_ghi  = %tq84_array(abc def ghi);
%let abc_def_ghi_ = %tq84_arrayMap(&abc_def_ghi, %nrstr(>&this<));

%tq84_arrayApply(&abc_def_ghi_, %nrstr(
  %put this = &this;
))
/*
this = >abc<
this = >def<
this = >ghi<
*/
Github repository about-SAS, path: /macros/tests/array/map.sas

Array of arrays

%let arrayOfArrays = %tq84_array();

%tq84_arrayPushBack(&arrayOfArrays, %tq84_array(one two three four));
%tq84_arrayPushBack(&arrayOfArrays, %tq84_array(foo bar baz));
%tq84_arrayPushBack(&arrayOfArrays, %tq84_array(what is this));
%tq84_arrayPushBack(&arrayOfArrays, %tq84_array(New York|Berlin|Zürich|Paris,delim=|));

%tq84_arrayApply(&arrayOfArrays, %nrstr(
   %put this = &this;
   %tq84_arrayApply(&this, %nrstr(
      %put %nrstr(  ) this = &this;
   ))
))

/*
this = tq84_array_33_
   this = one
   this = two
   this = three
   this = four
this = tq84_array_34_
   this = foo
   this = bar
   this = baz
this = tq84_array_35_
   this = what
   this = is
   this = this
this = tq84_array_36_
   this = New York
   this = Berlin
   this = Zürich
   this = Paris
*/

delim

When creating an array, the optional parameter delim can be used to specify the elements:
%let abcEtc = %tq84_array(abc-def-g h i-jkl, delim= -);
%tq84_arrayApply(&abcEtc, %nrstr(
  %put this = &this;
))
/*
this = abc
this = def
this = g h i
this = jkl
*/
Github repository about-SAS, path: /macros/tests/array/delim.sas

Name of array and its elements

%let array_1through4  = %tq84_array(one two three four);

%put array_1through4 = &array_1through4<;

%put &tq84_array_0_1; /* one   */
%put &tq84_array_0_2; /* two   */
%put &tq84_array_0_3; /* three */
%put &tq84_array_0_4; /* four  */

See also

Simulating arrays
macros

Index