From c85e1adfca24b62bb191d673b16645202e6f0ebe Mon Sep 17 00:00:00 2001 From: Bart Jablonski Date: Tue, 17 Feb 2026 14:52:03 +0100 Subject: [PATCH] The macroArray package, version: 1.3.2 The macroArray package, version: 1.3.2 Package regenerated with the SAS Packages Framework, version 20260216. No functional changes, aesthetic documentation clean up. - File SHA256: `F*35A657517CD2B1AB86C4E7C5320B5EDDDFBA9348075AE31DDAF875CF0CC193C9` for this version - Content SHA256: `C*DE477F4E280D438B364320F324C88DA3D336F102BA37810C60BDE15398DE84E9` for this version --- README.md | 2 +- hist/macroarray_1.3.2_.md | 2476 ++++++++++++++++++++++++++++++++++++ hist/macroarray_1.3.2_.zip | Bin 0 -> 56893 bytes macroarray.md | 20 +- macroarray.zip | Bin 56752 -> 56893 bytes 5 files changed, 2491 insertions(+), 7 deletions(-) create mode 100644 hist/macroarray_1.3.2_.md create mode 100644 hist/macroarray_1.3.2_.zip diff --git a/README.md b/README.md index 084163d..89e7abe 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The **macroArray** package implements an array, a hash table, and a dictionary c ); ``` -SHA256 digest for the latest version of `macroArray`: F*9DA64CA9A745E1DB7176F7AF4459BB014F61F71626473ABF6471A32689E14FF1 +SHA256 digest for the latest version of `macroArray`: F*35A657517CD2B1AB86C4E7C5320B5EDDDFBA9348075AE31DDAF875CF0CC193C9 [**Documentation for macroArray**](./macroarray.md "Documentation for macroArray") diff --git a/hist/macroarray_1.3.2_.md b/hist/macroarray_1.3.2_.md new file mode 100644 index 0000000..9b5446c --- /dev/null +++ b/hist/macroarray_1.3.2_.md @@ -0,0 +1,2476 @@ +# Documentation for the `macroArray` package. + +---------------------------------------------------------------- + + *Macroarrays for macro codes* + +---------------------------------------------------------------- + +### Version information: + +- Package: macroArray +- Version: 1.3.2 +- Generated: 2026-02-17T08:51:01 +- Author(s): Bartosz Jablonski (yabwon@gmail.com) +- Maintainer(s): Bartosz Jablonski (yabwon@gmail.com) +- License: MIT +- File SHA256: `F*35A657517CD2B1AB86C4E7C5320B5EDDDFBA9348075AE31DDAF875CF0CC193C9` for this version +- Content SHA256: `C*DE477F4E280D438B364320F324C88DA3D336F102BA37810C60BDE15398DE84E9` for this version + +--- + +# The `macroArray` package, version: `1.3.2`; + +--- + + +The **macroArray** package implements a macroarray facility. + +The set of macros, which emulates classic +data-step-array functionality on the macro +programming level, is provided. + +Some of components are: +- `%array()`, +- `%do_over()`, +- `%make_do_over()`, +- `%deletemacarray()`, +- `%concatarrays()`, +- `%appendcell()`, +- `%mcHashTable()`, +- `%zipArrays()`, +- `%sortMacroArray()`, +- `%mcDictionary()`, +- etc. + +Read this article to learn more: +"Macro Variable Arrays Made Easy with macroArray SAS Package" + +Link to the text: +`https://www.lexjansen.com/pharmasug/2024/AP/PharmaSUG-2024-AP-108.pdf` +or +`https://www.lexjansen.com/wuss/2024/124_FINAL_paper_pdf.pdf` + +*Note:* +If you are working with BIG macroarrays do not +forget to verify your session setting for macro +memory limits. Run: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + proc options group = macro; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +to verify the following options: + +| option | description | +|-------------:|:-----------------------------------------------------------------------------------------------| +|`MEXECSIZE=` | specifies the maximum macro size that can be executed in memory. | +|`MSYMTABMAX=` | specifies the maximum amount of memory available to the macro variable symbol table or tables. | +|`MVARSIZE=` | specifies the maximum size for a macro variable that is stored in memory. | + +--- + + +--- + + +--- + +Required SAS Components: + - Base SAS Software + +--- + + +--------------------------------------------------------------------- + +*SAS package generated by SAS Package Framework, version `20260216`,* +*under `WIN`(`X64_10PRO`) operating system,* +*using SAS release: `9.04.01M9P06042025`.* + +--------------------------------------------------------------------- + +# The `macroArray` package content +The `macroArray` package consists of the following content: + +1. [`%appendarray()` macro ](#appendarray-macro-1 ) +2. [`%appendcell()` macro ](#appendcell-macro-2 ) +3. [`%array()` macro ](#array-macro-3 ) +4. [`%concatarrays()` macro ](#concatarrays-macro-4 ) +5. [`%deletemacarray()` macro ](#deletemacarray-macro-5 ) +6. [`%do_over()` macro ](#doover-macro-6 ) +7. [`%do_over2()` macro ](#doover2-macro-7 ) +8. [`%do_over3()` macro ](#doover3-macro-8 ) +9. [`%make_do_over()` macro ](#makedoover-macro-9 ) +10. [`%mcdictionary()` macro ](#mcdictionary-macro-10 ) +11. [`%mchashtable()` macro ](#mchashtable-macro-11 ) +12. [`%qziparrays()` macro ](#qziparrays-macro-12 ) +13. [`%sortmacroarray()` macro ](#sortmacroarray-macro-13 ) +14. [`%ziparrays()` macro ](#ziparrays-macro-14 ) + + +15. [License note](#license) + +--- + +## `%appendarray()` macro ###### + +The `%appendArray()` macro is a macrowrapper +which allows to concatenate two macroarrays +created by `%array()` macro. + +By default values of the second macroarray are *not* removed. + +Dimensions of the first macroarray are extended. + +The `%appendArray()` macro executes like a pure macro code. + +### SYNTAX: ##################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%appendArray( + first + ,second +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `first` - *Required*, a name of a macroarray created by the `%array()` macro. + +2. `second` - *Required*, a name of a macroarray created by the `%array()` macro. + + +### EXAMPLES AND USECASES: ###################################################### + +**EXAMPLE 1.** Append macroarrays LL and MM. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(ll[2:4] $ 12, + function = quote(put(today() + 10*_I_, yymmdd10.)), + macarray=Y + ) + %array(mm[10:13] $ 1200, + function = quote(repeat("A",12*_I_)), + macarray=Y + ) + %put *%ll(2)*%ll(3)*%ll(4)*; + + %appendArray(ll, mm); + %put *%ll(2)*%ll(3)*%ll(4)*%ll(5)*%ll(6)**%ll(7)*%ll(8)*; + + %put *%mm(10)**%mm(11)*%mm(12)*%mm(13)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Error handling. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %appendArray(ll, ) + %appendArray(, mm) + + %appendArray(noExistA, noExistB) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--- + + +--- + +## `%appendcell()` macro ###### + +The `%appendCell()` macro allows to append +a macrovariable to a macroarray created by the `%array()` macro. + +Dimensions of the macroarray are extended. + +The `%appendCell()` macro executes like a pure macro code. + +### SYNTAX: #################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%appendCell( + first + ,second + ,hilo +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `first` - *Required*, a name of a macroarray created by the `%array()` macro. + +2. `second` - *Required*, a name of a macrovariable to be append to the macroarray. + +3. `hilo` - *Required*, if `H` macrovariable is appended at the end + if `L` macrovariable is appended at the beginning + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Create two macro wrappers. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %* Macro wrapper to append a macrovariable to the end of a macroarray; + %macro appendHC(array,cell); + %appendCell(&array.,&cell.,H) + %mend appendHC; + + %* macro wrapper to append a macrovariable to the beginning of a macroarray; + %macro appendLC(array,cell); + %appendCell(&array.,&cell.,L) + %mend appendLC; + + + %* create macroarrays X and variables W,Y,Z; + + %array(X[2:4] $ ("AAA", "BBB", "CCC"), macarray=Y) + %let W=1; + %let Y=2; + %let Z=3; + %put *%do_over(X)*&=W*&=Y*&=Z*; + + %put BEFORE *%do_over(X)**&=xLBOUND*&=xHBOUND*&=xN*; + %appendCell(X,Y,H) + %put AFTER1 *%do_over(X)**&=xLBOUND*&=xHBOUND*&=xN*; + + %appendLC(X,W) + %put AFTER2 *%do_over(X)**&=xLBOUND*&=xHBOUND*&=xN*; + + %appendHC(X,Z) + %put AFTER3 *%do_over(X)**&=xLBOUND*&=xHBOUND*&=xN*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Error handling +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %appendCell(X,Y,blahblah) + + %appendCell(X,,H) + %appendCell(,Y,H) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 3.** Adding variable below lower bound. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(zero[0:2] $ ("AAA", "BBB", "CCC"), macarray=Y) + %let belowzero=zzz; + + %put BEFORE *%do_over(zero)**&=zeroLBOUND*&=zeroHBOUND*&=zeroN*; + %appendCell(zero,belowzero,L) + %put AFTER *%do_over(zero)**&=zeroLBOUND*&=zeroHBOUND*&=zeroN*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--- + + +--- + +## `%array()` macro ###### + +The code of a macro was inspired by +*Ted Clay's* and *David Katz's* macro `%array()`. + +The `%array()` macro version provided in the package +is designed to facilitate +the idea of macroarray concept, i.e. *a list of +macrovariables with common prefix and numerical suffixes*. +Usually such construction is then resolved by +double ampersand syntax, e.g. `&&perfix&i` or similar one. + +What is new/extension to the `%array()` macro concept are: + +0. The syntax is closer to the data step one. +1. It is a pure macro code (it can be executed in any place + of 4GL code), this includes generating macroarrays out + of datasets. +2. When a macroarrray is created it allows also to generate + a new macro (named the same as the array name) and replace + the double ampersand syntax with more array looking one, + i.e. for array ABC user can have `%ABC(1)`, `%ABC(2)`, or `%ABC(&i)` + constructions. +3. The array macro allows to use data step functions to generate + array's entries. + +The `%array()` macro executes like a pure macro code. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%array( + array + <,function=> + <,before=> + <,after=> + <,vnames=N> + <,macarray=N> + <,ds=> + <,vars=> + <,q=> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `array` - *Required*, an array name and a declaration/definition of an array,
+ e.g. `myArr[*] x1-x3 (4:6)`
+ or `myBrr[*] $ y1-y3 ("a" "b" "c")`
+ or `myCrr[3] $ ("d d d" "e,e,e" "f;f;f")`
+ or `myDrr p q r s`.
+ Macrovariables created by the macro are *global*. + If an array name is `_` (single underscore) then attached variables + list names are used, a call of the form: + `%array(_[*] p1 q2 r3 s4 (-1 -2 -3 -4))` + will create macrovariables: `p1`, `q2`, `r3`, and `s4` with respective + values: `-1`, `-2`, `-3`, and `-4`.
+ Three additional *global* macrovariables: + `LBOUND`, `HBOUND`, and `N` + are generated with the macroarray. See examples for more use-cases. + +* `function=` - *Optional*, a function or an expression to be applied to all array cells, + `_I_` is as array iterator, e.g. `_I_ + rand("uniform")`. + +* `before=` - *Optional*, a function or an expression to be added before looping through + array, e.g. `call streaminit(123)`. + +* `after=` - *Optional*, a function or an expression to be added after looping through + array, e.g. `call sortn(ABC)`. + +* `vnames=N` - *Optional*, default value `N`, if set to `Y`/`YES` then macroarray is built based + on variables names instead values, e.g. + `%array(myArr[*] x1-x3 (4:6), vnames=Y)` + will use `x1`, `x2`, and `x3` as values instead `4`, `5`, and `6`. + +* `macarray=N` - *Optional*, default value `N`, if set to `Y`/`YES` then a macro, named with the array + name, is compiled to create convenient envelope for multiple ampersands, e.g. + `%array(myArr[*] x1-x3 (4:6), macarray=Y)` + will create `%myArr(J)` macro which will allow to extract "data" + from macroarray like: + `%let x = %myArr(1);` + or when used with second parameter equal `I` (insert) allow to overwrite macroarrays + value: + `%let %myArr(17,i) = 42;` + If set to `M` then for a given array name the macro symbols table is scanned for + macrovariables with prefix like the array name and numeric suffixes, + then the minimum and the maximum index is determined + and all not existing global macrovariables are created and + a macro is generated in the same way as for the `Y` value. + +* `ds=` - *Optional*, use a dataset as a basis for a macroarray data, + if used by default overwrites use of the `array` parameter, honors `macarray=` + argument, dataset options are allowed, e.g. `sashelp.class(obs=5)` + +* `vars=` - *Optional*, a list of variables used to create macroarrays from a dataset, + the list format can be as follows (`<...>` means optional): + `variable1 <... variableN>` + delimiters are hash(`#`) and pipe(`|`), currently only space + is supported as separator, the meaning of `#` and `|` delimiters + will be explained in the following example: + if the `vars = height#h weight weight|w age|` value is provided + then the following macroarrays will be created:
+ 1) macroarray "H" with ALL(`#`) values of variable "height"
+ 2) macroarray "WEIGHT" with ALL(no separator is equivalent to #) + values of variable "weight"
+ 3) macroarray "W" with UNIQUE(|) values of variable "weight" and
+ 4) macroarray "AGE" with UNIQUE(|) values of variable "age". + +* `q=` - *Optional*, indicates (when set to `1` or '2') if the value should be surrounded by quotes. + It uses `quote(cats(...))` combo under the hood. Default value is `0`. + Value `1` is for apostrophes, value `2` is for double quotes. + Ignored for `macarray=M`. + + +### EXAMPLES AND USECASES: #################################################### + + +**EXAMPLE 1.** Basic use-case. + Creating macroarray like in the array statement. + Values not variables names are used by default. + Different types of brackets are allowed. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(a[*] x1-x5 (1:5)) + + %array(b{5} (5*17), q=1) + + %* Mind the $ since it is a character array!; + %array(c(3) $ 10 ("a A" "b,B" "c;C")) + + %array(d x1-x5 (5 4 3 2 1)) + %put _user_; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Index ranges. + If range starts < 0 then it is shifted to 0. + In case when range is from `1` to `M` + then macrovariable `N` is set to `M` + In case when range is different + the `N` returns number of + elements in the array `(Hbound - Lbound + 1)`. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(d[-2:2] $ ("a" "b" "c" "d" "e")) + %put &=dLBOUND. &=dHBOUND. &=dN.; + %put &=d0. &=d1. &=d2. &=d3. &=d4.; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 3.** Functions. + It is possible to assign value of a function + or an expression to a cell of the array, + e.g. `array[_I_] = function(...)`. + You can use an iterator in a function. + As in case of usual arrays it is `_I_`. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(e[-3:3] $, function = "A" ) + %put &=eLBOUND. &=eHBOUND. &=eN.; + %put &=e0. &=e1. &=e2. &=e3. &=e4. &=e5. &=e6.; + + %array(f[-3:3], function = (2**_I_) ) + %put &=fLBOUND. &=fHBOUND. &=fN.; + %put &=f0. &=f1. &=f2. &=f3. &=f4. &=f5. &=f6.; + + %array(g[0:2], function = ranuni(123) ) + %put &=gLBOUND. &=gHBOUND. &=gN.; + %put &=g0. &=g1. &=g2.; + + %* Or something more complex; + %array(gg[0:11] $ 11, function = put(intnx("MONTH", '1jun2018'd, _I_, "E"), yymmn.), q=1) + %put &=ggLBOUND. &=ggHBOUND. &=ggN.; + %put &=gg0 &=gg1 &=gg2 ... &=gg11; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 4.** Functions cont. + If there is need for set-up something *before* or *after*: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(h[10:12] + ,function = rand('Uniform') + ,before = call streaminit(123) + ,after = call sortn(of h[*]) + ) + %put &=h10. &=h11. &=h12.; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 5.** Fibonacci series. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(i[1:10] (10*0) + ,function = ifn(_I_ < 2, 1, sum(i[max(_I_-2,1)], i[max(_I_-1,2)]) ) ) + %put &=i1 &=i2 &=i3 &=i4 &=i5 &=i6 &=i7 &=i8 &=i9 &=i10; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 6a.** Quoted "Uppercas Letters" + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(UL[26] $, function = byte(rank("A")+_I_-1) , q=1) + %put &=UL1 &=UL2 ... &=UL25 &=UL26; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 6b.** "Lowercase Letters" + Extended by `macarray=Y` option and + the input mode support (with `I`). + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(ll[26] $, function = byte(rank("a")+_I_-1), macarray=Y) + %put *%ll(&llLBOUND.)*%ll(3)*%ll(4)*%ll(5)*...*%ll(25)*%ll(&llHBOUND.)*; + + %* The range handling, warning; + %put *%ll(265)*; + + %* The input mode; + %put *before:*%ll(2)*; + %let %ll(2,I) = bbbbb; + %put *after: *%ll(2)*; + + %* The range handling, error; + %let %ll(265,I) = bbb; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 7.** The use of `vnames=Y` + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(R R1978-R1982) + %put &=R1 &=R2 &=R3 &=R4 &=R5; + + %array(R R1978-R1982 (78:82)) + %put &=R1 &=R2 &=R3 &=R4 &=R5; + + %array(R R1978-R1982 (78:82), vnames=Y) + %put &=R1 &=R2 &=R3 &=R4 &=R5; + + %array(R R1978-R1982, vnames=Y) + %put &=R1 &=R2 &=R3 &=R4 &=R5; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 8.** A "no name" array i.e. the `_[*]` array + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(_[*] x1-x5 (1:5)) + %put _user_; + + %array(_[*] p q r s (4*42)) + %put _user_; + + %* If no variables names than use _1 _2 ... _N; + %array(_[4] (-1 -2 -3 -4)) + %put &=_1 &=_2 &=_3 &=_4; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 9.** Pure macro code can be used in a data step. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + data test1; + set sashelp.class; + %array(ds[*] d1-d4 (4*17)) + a1 = &ds1.; + a2 = &ds2.; + a3 = &ds3.; + a4 = &ds4.; + run; + + data test2; + set sashelp.class; + %array(_[*] j k l m (4*17)) + a1 = &j.; + a2 = &k.; + a3 = &l.; + a4 = &m.; + run; + + data test3; + set sashelp.class; + %array(alpha[*] j k l m (101 102 103 104), macarray=Y) + a1 = %alpha(1); + a2 = %alpha(2); + a3 = %alpha(3); + a4 = %alpha(4); + a5 = %alpha(555); + run; + + data test4; + set sashelp.class; + %array(beta[*] j k l m (101 102 103 104), vnames=Y, macarray=Y) + a1 = "%beta(1)"; + a2 = "%beta(2)"; + a3 = "%beta(3)"; + a4 = "%beta(4)"; + a5 = "%beta(555)"; + run; + + data test5; + set sashelp.class; + %array(gamma[4] $ 12 ("101" "102" "103" "104"), macarray=Y) + a1 = "%gamma(1)"; + a2 = "%gamma(2)"; + a3 = "%gamma(3)"; + a4 = "%gamma(4)"; + a5 = "%gamma(555)"; + run; + + data test6; + set sashelp.class; + %array(ds = sashelp.cars, vars = Cylinders|, macarray=Y) + a0 = %Cylinders(0); + a1 = %Cylinders(1); + a2 = %Cylinders(2); + a3 = %Cylinders(3); + a4 = %Cylinders(4); + a5 = %Cylinders(555); + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 10.** Creating an array from a dataset, basic case. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(ds = sashelp.class, vars = height weight age) + %put _user_; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 11. Creating an array from a dataset, advanced. + If: `vars = height#h weight weight|w age|` + then create: + 1. macroarray "h" with ALL(#) values of variable "height" + 2. macroarray "weight" with ALL(no separator is equivalent to #) values of variable "weight" + 3. macroarray "w" with UNIQUE(|) values of variable "weight" + 4. macroarray "age" with UNIQUE(|) values of variable "age" + Currently the only separator in VARS is a space. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(ds = sashelp.class, vars = height#h weight weight|w age|, q=1) + %put _user_; + + %array(ds = sashelp.class, vars = height#hght weight weight|wght age|, macarray=Y, q=1) + %put *%hght(&hghtLBOUND.)**%weight(2)**%wght(&wghtHBOUND.)**%age(3)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 12.** Creating an array from a dataset with dataset options + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(ds = sashelp.cars(obs=100 where=(Cylinders=6)), vars = Make| Type| Model, macarray=Y) + %put *%make(&makeLBOUND.)*%Model(2)*%Model(3)*%Model(4)*%type(&typeHBOUND.)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 13.** Creating an array and macro from existing list of macrovariables + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %let myTest3 = 13; + %let myTest6 = 16; + %let myTest9 = 19; + + %array(myTest, macarray=M, q=1) + %do_over(myTest, phrase = %nrstr(%put *&_I_.*%myTest(&_I_.)*;)) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `%concatarrays()` macro ###### + + +The `%concatArrays()` macro allows to concatenate +two macroarrays created by the `%array()` macro. + +By default values of the second macroarray are removed. + +Dimensions of the first macroarray are extended. + +The `%concatArrays()` macro executes like a pure macro code. + +### SYNTAX: ##################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%concatArrays( + first + ,second + <,removeSecond=Y> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `first` - *Required*, a name of a macroarray created by the `%array()` macro. + +2. `second` - *Required*, a name of a macroarray created by the `%array()` macro. + +* `removeSecond=Y` - *Optional*, default value `Y`, if set to `Y` then + the second array is removed. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Concatenate macroarrays LL and MM. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(ll[2:4] $ 12, + function = quote(put(today() + 10*_I_, yymmdd10.)), + macarray=Y + ) + %array(mm[10:13] $ 12000, + function = quote(repeat("A",123*_I_)), + macarray=Y + ) + %put *%ll(2)*%ll(3)*%ll(4)*; + + %concatArrays(ll, mm); + %put *%ll(2)*%ll(3)*%ll(4)*%ll(5)*%ll(6)**%ll(7)*%ll(8)*; + + %put *%mm(10)**%mm(11)*%mm(12)*%mm(13)*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Error handling. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %concatArrays(ll, ) + %concatArrays(, mm) + + %concatArrays(noExistA, noExistB) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--- + + +--- + +## `%deletemacarray()` macro ###### + +The `%deleteMacArray()` macro allows to delete +macroarrays created by the `%array()` macro. + +The `%deleteMacArray()` macro executes like a pure macro code. + +### SYNTAX: ##################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%deleteMacArray( + arrs + <,macarray=N> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `arrs` - *Required*, a space separated list of manes + of macroarray created by the `%array()` macro. + +* `macarray=N` - *Optional*, indicator should a macro + associated with macroarray to be deleted? + If `Y` or `YES` then the associated macro is deleted. + + +--- + +## `%do_over()` macro ###### + +The code of the macro was inspired by +*Ted Clay's* and *David Katz's* macro `%do_over()`. + +The `%DO_OVER()` macro allows to iterate over macroarray created with +the `macarray=Y` parameter of the `%ARRAY()` macro. + +The `%do_over()` macro executes like a pure macro code. + +### SYNTAX: ##################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%do_over( + arrays + <,phrase = %nrstr(%&array(&_I_.))> + <,between = %str( )> + <,which = > + <,check = 0> + <,rephrase = > + <,trigger = ?> + <,unq = 1> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `arrays` - *Required*, a space-separated list of macroarrays names. + The first one identifies the macroarray which metadata + (Lbound, Hbouns, and N) are used to loop in the `%do_over()`. + +* `phrase=` - *Optional*, Default value `%nrstr(%&array(&_I_.))`, + a statement to be called in each iteration + of the internal do_over's loop. Loop iterator is `_I_`, + if you want to use `_I_` or array name + [e.g. `%myArr(&_I_.)`] *enclose it* in the `%NRSTR()` + macro quoting function. + +* `between=` - *Optional*, default value `%str( )` (space), + a statement to be called in between each + iteration of the internal do_over loop. + If macroquoted (e.g. `%str( + )`) then the `%unquote()` + function is automatically applied. + +* `which=` - *Optional*, a space-separated list of indexes which + should be used to iterate over selected macroarray. + Possible special characters are `H` and `L` which means + *high* and *low* bound of an array, list could be set with + colons(`:`) in form of `start:end:by` (*no spaces between!*), + if `by` is omitted the default is `1`. If possible use + `1:5` rather `1 2 3 4 5` since the firs works faster. + +* `check=` - *Optional*, indicates should a check for a macro corresponding + to a macroarray be executed. If the macro does not exist warning + is issued and the `do_over` stops. + Default value `0` means: do not execute check. + +* `rephrase=` - *Optional*, this parameter allows for an alternative approach + in providing the phrase to be looped over. The idea is to make + writing the phrase string code more convenient and easy to grasp. + The value is a string containing triggers (symbols) that are + replaced by proper macroarray calls. For example, if a macroarray + `myArr` has 7 values form `varName1` to `varName7` and you want + to use them as arguments in code renaming variables, say + `rename old_varName1=new_varName1 ... ;`, instead typing phrase: + `rename %do_over(myArr,phrase=%nrstr(old_%myArr(&_I_.)=new_%myArr(&_I_.)));` + you can type much easier rephrase: + `rename %do_over(myArr,rephrase=old_?=new_?);`, + and all `?` will be replaced, under the hood, by calls to the macroarray. + For easier debugging the `do_over` macro prints the rephrased string + before and after change. + When the `do_over` loops with multiple array, say `myArrA`, `myArrB`, + and `myArrC`, then those arrays should be referred by `?1?`, `?2?`, + and `?3?` respectively. + See `trigger` parameter definition to learn more. + If both `phrase` and `rephrase` are used, the second takes precedence. + +* `trigger=` - *Optional*, a single byte character (symbol) used for marking + macroarrays in the newly created phrase. + Default value is `?` symbol. + When one macroarray is used, only the symbol should be used in + `rephrase=` string. When multiple macroarrays are used then the + symbol should surround a number identifying array, e.g. `?2?`. + See examples below for details. + +* `unq=` - *Optional*, indicates that the `%unquote()` macro function should + be added around every macroarray call. Because of SAS internal + behavior `unq=1` is needed for certain cases when plain 4GL code + is used in `rephrase=`. For example, let macro array `myArr()` + has 3 values: `A1`, `B2`, and `C3`. When the following code + is run: `%do_over(myArr, rephrase=data ?_test; run;)` without + `unq=1`, SAS will create 4 data sets: `A1`, `B2`, `C3`, + and `_test`, instead 3 data sets: `A1_test`, `B2_test`, and `C3_test`. + Default value `1` means: add the `%unquote()`. + See example below to learn more. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Simple looping. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(beta[*] j k l m (101 102 103 104), vnames=Y, macarray=Y) + + %put #%do_over(beta)#; + + %put #%do_over(beta, phrase=%nrstr("%beta(&_I_.)"), between=%str(,))#; + + data test1; + %array(beta[*] j k l m (101 102 103 104), vnames=Y, macarray=Y) + %do_over(beta, phrase=%nrstr(a&_I_. = "%beta(&_I_.)";)) + put _all_; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Multiple arrays looping. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(alpha[*] j k l m n, vnames=Y, macarray=Y) + %array( beta[5] $ , function = "a", macarray=Y) + %array(gamma[4] (101 102 103 104), macarray=Y) + + data test2; + call streaminit(123); + %do_over(beta + , phrase = %nrstr(%beta(&_I_.) = %gamma(&_I_.) * rand('Uniform'); output;) + , between = put _all_; + ); + put _all_; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 3.** Multiple arrays looping, cont. + Create multiple datasets. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %do_over(beta + , phrase = %nrstr( + data %alpha(&_I_.)2; + call streaminit(123); + %beta(&_I_.)x = %gamma(&_I_.) * rand('Uniform'); + output; + run; + ) + ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 4.** Multiple arrays looping, cont. + Create multiple datasets using a macro. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %macro doit(ds, var=a, val=1); + data &ds.; + call streaminit(123); + &var. = &val. * rand('Uniform'); + output; + run; + %mend doit; + + %do_over(beta + , phrase = %nrstr( + %DOIT(%alpha(&_I_.)1, var = %beta(&_I_.), val = %gamma(&_I_.)) + ) + ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 5.** `%do_over()` inside `%array()` + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(test[*] x1-x12 (1:12), macarray=Y) + + %put **%test(1)**%test(12)**; + + %put #%do_over(test)#; + + %array(abc[*] x1-x12 (%do_over(test,phrase=%nrstr(%eval(100-%test(&_I_.))))), macarray=Y) + + %put **%abc(1)**%abc(12)**; + + %put #%do_over(abc)#; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 6.** Looping over array with *macroquoted* separator. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(alpha[11] (5:15), macarray=Y) + + %let x = %do_over(alpha + , between= %str( + ) + ); + %put &=x.; + %put %sysevalf(&x.); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 7.** Working with the `WHICH=` optional parameter + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(test[*] x01-x12, vnames= Y, macarray=Y) + + %put #%do_over(test)#; + + %put #%do_over(test, which= 1 3 5)#; + + %put #%do_over(test, which= 1:5)#; + + %put #%do_over(test, which= 1:5:2 7 8)#; + + %put #%do_over(test, which= L:H l:h)#; + + %put #%do_over(test, which= L:3 10:h)#; + + %put #%do_over(test, which= L:H h:l:-1 13 14)#; + + %put #%do_over(test, which= %eval(1+1):%eval(5+1))#; + + %put #%do_over(test, which= L:H h:l:-1 13 14, between=%str(,))#; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 8.** Simpler multiple arrays looping with `rephrase=`. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(alpha[*] j k l m n o p, vnames=Y, macarray=Y) + %array( beta[&alphaN.], function = (2**_i_), macarray=Y) + %array(gamma[&alphaN.] (1:&alphaN.), macarray=Y) + + %put >>%do_over(alpha)<<; + %put >>%do_over(beta)<<; + %put >>%do_over(gamma)<<; + + data test8; + call streaminit(123); + + %do_over( alpha beta gamma + , rephrase = ?1? = ?2? + ?3? * rand('Uniform'); output; + , between = put _all_; + ) + put _all_; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 9.** Simpler multiple arrays looping with `rephrase=`, cont. + Create multiple datasets. Array `alpha`, `beta`, and `gamma` are + from the previous example. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %do_over(alpha beta gamma + , rephrase = + data ?1?_2; + call streaminit(?2?); + ?1?X = ?2? + ?3? * rand('Uniform'); + output; + run; + ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 10.** Simpler multiple arrays looping with `rephrase=`, cont. + Create multiple datasets using a macro. Array `alpha`, `beta`, + and `gamma` are from the previous example. + The `%nrstr()` is required to mask call to the `%doit2()` macro. + Default `?` is replaced with `@`. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %macro doit2(ds, var=a, val1=1, val2=2); + data &ds._3; + call streaminit(&val1.); + &var. = &val1. + &val2. * rand('Uniform'); + output; + run; + %mend doit2; + + %do_over( alpha beta gamma + , rephrase = %nrstr(%doit2(@1@, var = @1@, val1 = @2@, val2 = @3@)) + , trigger = @ + ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 11.** Simpler multiple arrays looping with `rephrase=`, cont. + Why the `unq=` is needed. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(myArr[3] $ ("A1" "B2" "C3"), macarray=Y) + + %do_over(myArr, rephrase=data ?_testUNQ1; run;, unq=1) + + %do_over(myArr, rephrase=data ?_testUNQ0; run;, unq=0) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + + +**EXAMPLE 12.** Simpler multiple arrays looping with `rephrase=`, cont. + Renaming variables is easy now. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(V[*] a b c d e f g h, vnames=1, macarray=1) + + data test12; + array x{*} %do_over(V) (1:&VN.); + run; + + proc datasets nolist noprint lib=work; + modify test12; + rename + %do_over(V,rephrase = $=new_$,trigger=$) + ; + run; + quit; + + data _null_; + set test12; + put _ALL_; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +--- + +--- + +## `%do_over2()` macro ###### + +The code of the macro was inspired by +*Ted Clay's* and *David Katz's* macro `%do_over()`. + +The `%DO_OVER2()` macro allows to iterate over *two* macroarray created with +the `macarray=Y` parameter of the `%ARRAY()` macro. + +The `%do_over2()` macro executes like a pure macro code. + +### SYNTAX: ##################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%do_over2( + arrayI + ,arrayJ + <,phrase=%nrstr(%&arrayI(&_I_.) %&arrayJ(&_J_.))> + <,between=%str( )> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `arrayI` - Required, indicates the first macroarray which metadata (Lbound, Hbouns) + are to be used in the outer loop in the `%do_over2()` + +2. `arrayJ` - Required, indicates the second macroarray which metadata (Lbound, Hbouns) + are to be used in the inner loop in the `%do_over2()` + +* `phrase=` - *Optional*, default value `%nrstr(%&arrayI(&_I_.) %&arrayJ(&_J_.))`, + a statement to be called in each iteration + of the *inner* loop. The outer loop iterator is `_I_`, + the inner loop iterator is `_J_`, + if you want to use `_I_`, `_J_`, or arrays names + [e.g. `%myArr(&_I_.)`] *enclose them* in the `%NRSTR()` + macro quoting function. + +* `between=` - *Optional*, default value `%str( )` (space), + a statement to be called in between each + iteration of the internal do_over2 loop. + If macroquoted (e.g. `%str( + )`) then the `%unquote()` + function is automatically applied. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Looping over two arrays. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(alpha[*] j k l m n, vnames=Y, macarray=Y) + %array( beta[4] (101 102 103 104), macarray=Y) + + %put *%do_over2(alpha, beta + , phrase = %NRSTR((%alpha(&_I_.), %beta(&_J_))) + )*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Looping over two arrays with a separator. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(alpha[11] (5:15), macarray=Y) + %array( beta[ 4] (101 102 103 104), macarray=Y) + + %let x = %do_over2(alpha, beta + , phrase = %NRSTR((%alpha(&_I_.) * %beta(&_J_))) + , between= + + ); + %put &=x.; + %put %sysevalf(&x.); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 3.** Looping over two arrays with *macroquoted* separator. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(alpha[11] (5:15), macarray=Y) + %array( beta[ 4] (101 102 103 104), macarray=Y) + + %let x = %do_over2(alpha, beta + , phrase = %NRSTR((%alpha(&_I_.) * %beta(&_J_))) + , between= %str( + ) + ); + %put &=x.; + %put %sysevalf(&x.); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--- + +--- + +## `%do_over3()` macro ###### + +The code of the macro was inspired by +*Ted Clay's* and *David Katz's* macro `%do_over()`. + +The `%DO_OVER3()` macro allows to iterate over *three* macroarray created with +the `macarray=Y` parameter of the `%ARRAY()` macro. + +The `%do_over3()` macro executes like a pure macro code. + +### SYNTAX: ##################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%do_over2( + arrayI + ,arrayJ + ,arrayK + <,phrase=%nrstr(%&arrayI(&_I_.) %&arrayJ(&_J_.) %&arrayK(&_K_.))> + <,between=%str( )> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `arrayI` - *Required*, indicates the first macroarray which metadata (Lbound, Hbouns) + are to be used in the outer loop in the `%do_over3()` + +2. `arrayJ` - *Required*, indicates the second macroarray which metadata (Lbound, Hbouns) + are to be used in the inner loop in the `%do_over3()` + +3. `arrayK` - *Required*, indicates the third macroarray which metadata (Lbound, Hbouns) + are to be used in the inner loop in the `%do_over3()` + +* `phrase=` - *Optional*, default value `%nrstr(%&arrayI(&_I_.) %&arrayJ(&_J_.) %&arrayK(&_K_.))`, + a statement to be called in each iteration + of the *inner* loop. The *outer* loop iterator is `_I_`, + the *middle* loop iterator is `_J_`, the *inner* loop iterator is `_K_`, + if you want to use `_I_`, `_J_`, `_K_`, or arrays names + [e.g. `%myArr(&_I_.)`] *enclose them* in the `%NRSTR()` + macro quoting function. + +* `between=` - *Optional*, default value `%str( )` (space), + a statement to be called in between each + iteration of the internal do_over2 loop. + If macroquoted (e.g. `%str( + )`) then the `%unquote()` + function is automatically applied. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Looping over 3 macroarrays. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(a1_[2] (0 1), macarray=Y) + %array(a2_[2] (2 3), macarray=Y) + %array(a3_[2] (4 5), macarray=Y) + + %do_over3(a1_, a2_, a3_ + , phrase = %NRSTR(%put (%a1_(&_I_.), %a2_(&_J_), %a3_(&_K_));) + ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 2.** Looping 3 times over a macroarray. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(a[0:2] (0 1 2), macarray=Y) + + %do_over3(a, a, a + , phrase = %NRSTR(%put (%a(&_I_.), %a(&_J_), %a(&_K_));) + ) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--- + +--- + +## `%make_do_over()` macro ###### + +The code of the macro was inspired by +*Ted Clay's* and *David Katz's* macro `%do_over()`. + +The `%make_do_over()` macro allows to generate +the `%DO_OVER()` macros. It works *only* for *n>3*! + +The `%make_do_over()` macro does *not* executes like a pure macro code. + +### SYNTAX: ##################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%make_do_over( + size +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `size` - *Required*, indicates the number of dimensions + (i.e. inner loops) of the `%DO_OVER()` macro. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Code of created "4-loop" `%DO_OVER4()` macro + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %macro do_over4( + arrayI1, + arrayI2, + arrayI3, + arrayI4, + phrase=%nrstr( + %&arrayI1(&_I1_.) + %&arrayI2(&_I2_.) + %&arrayI3(&_I3_.) + %&arrayI3(&_I4_.) + ), + between=%str( ) + ); + %local _I1_ _I2_ _I3_ _I4_; + %do _I1_ = &&&arrayI1.LBOUND %to &&&arrayI1.HBOUND; + %do _I2_ = &&&arrayI2.LBOUND %to &&&arrayI2.HBOUND; + %do _I3_ = &&&arrayI3.LBOUND %to &&&arrayI3.HBOUND; + %do _I4_ = &&&arrayI4.LBOUND %to &&&arrayI4.HBOUND; + %if not ( + &_I1_. = &&&arrayI1.LBOUND + AND &_I2_. = &&&arrayI2.LBOUND + AND &_I3_. = &&&arrayI3.LBOUND + AND &_I4_. = &&&arrayI4.LBOUND + ) + %then %do;%unquote(&between.)%end;%unquote(%unquote(&phrase.)) + %end; + %end; + %end; + %end; + %mend do_over4; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Create a "4-loop" `%DO_OVER4()` macro + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %make_do_over(4); + + %array(a1_[2] (0 1), macarray=Y) + + %do_over4(a1_, a1_, a1_, a1_ + , phrase = %NRSTR(%put (%a1_(&_I1_.), %a1_(&_I2_), %a1_(&_I3_), %a1_(&_I4_));) + ) + + %put *%do_over4(a1_, a1_, a1_, a1_ + , between = * + )*; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 3.** Create a "5-loop" `%DO_OVER5()` macro + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %make_do_over(5); + + %array(a1_[2] (0 1), macarray=Y) + + %do_over5(a1_, a1_, a1_, a1_, a1_ + , phrase = %NRSTR(%put (%a1_(&_I1_.), %a1_(&_I2_), %a1_(&_I3_), %a1_(&_I4_), %a1_(&_I5_));) + ) + + %put *%do_over5(a1_, a1_, a1_, a1_, a1_ + , between = * + )* + ; + + options nomprint; + data test2; + %do_over5(a1_, a1_, a1_, a1_, a1_ + , phrase = %NRSTR(x1 = %a1_(&_I1_.); x2 = %a1_(&_I2_); x3 = %a1_(&_I3_); x4 = %a1_(&_I4_); x5 = %a1_(&_I5_);) + , between = output; + ) + output; + run; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 4.** Create all from 6 to 10 "do_overs" + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + %array(loop[6:10] (6:10), macarray=Y) + %do_over(loop + , phrase = %nrstr( + %make_do_over(%loop(&_I_.)) + ) + ); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--- + +--- + +## `%mcdictionary()` macro ###### + +The `%mcDictionary()` macro provided in the package +is designed to facilitate the idea of a "macro dictionary" +concept, i.e. *a list of macrovariables with common prefix +and suffixes generated as a hash digest* which allows +to use values other than integers as indexes. + +The `%mcDictionary()` macro allows to generate other macros +which behaves like a dictionary. See examples below. + +The `%mcDictionary()` macro executes like a pure macro code. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%mcDictionary( + H + <,METHOD> + <,DS=> + <,K=Key> + <,D=Data> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `H` - *Required*, a dictionary macro name and a declaration/definition, + e.g. `mcDictionary(HT)`. It names a macro which is generated by + the `%mcDictionary()` macro. Provided name cannot be empty + or an underscore (`_`). No longer than *13* characters. + +2. `METHOD` - *Optional*, if empty (or DECLARE or DCL) then the code of + a macro dictionary is compiled. + If `DELETE` then the macro dictionary named by `H` and all + macrovariables named like "`&H._`" are deleted. + +* `DS=` - *Optional*, if NOT empty then the `&DS.` dataset is used to + populate dictionary with keys from variable `&K.` and data + from variable `&D.` Works only during declaration. + +* `K=` - *Optional*, if the `&DS.` is NOT empty then `&K.` holds a name of + a variable which keeps or an expression which generates keys values. + Default is `Key`. + +* `D=` - *Optional*, if the `&DS.` is NOT empty then `&D.` holds a name of + a variable which keeps or an expression which generates data values. + Default is `Data`. + +--- + +### THE CREATED MACRO `%&H.()`: #################################################### + +The created macro imitates behaviour of a dictionary. + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%&H.( + METHOD + <,KEY=> + <,DATA=> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `METHOD` - *Required*, indicate what behaviour should be executed. + Allowed values are: + - `ADD`, adds key and data portion to the macro dictionary, + *multiple data portions* are NOT available for one key. + - `FIND`, tests if given key exists in the macro dictionary + and, if yes, returns data value associated with the key. + For multiple data portions see the `data=` parameter. + - `CHECK`, returns indicator if the key exists in dictionary. + - `DEL`, removes key and data portion from the macro dictionary. + - `LIST`, prints out a dictionary to the log. + - `CLEAR` removes all data and keys values. + +* `KEY=` - *Optional*, provides key value for `ADD`, `FIND`, `CHECK` + and `DEL` methods. + Leading and trimming spaces are removed from the value. + The `MD5(...)` function is used to generate the hash. + Default value is `_`. + +* `DATA=` - *Optional*, provides data value for the `ADD` method. + Default value is blank. + + +When macro is executed and when data are added the following types of +*global* macrovariables are created: +- `&H._########_K`, +- `&H._########_V`, +- `&H._KEYSNUM`. + +The `#` represents value generated by the `MD5(...)` function for the given key. + +The first type keeps information about the key. + +The second type keeps information about the value of a given key + +The third type keeps the number of unique values of the key. + +See examples below to see use cases. + +--- + +### EXAMPLES AND USECASES: #################################################### + + +**EXAMPLE 1.** Basic use-case. + Creating macro dictionary, macro `Dict` is generated. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%mcDictionary(Dict) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Add elements to the `Dict`. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%Dict(ADD,key=x,data=17) +%Dict(ADD,key=y y,data=42) +%Dict(ADD,key=z z z,data=303) + +%put _user_; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Add some duplicates for the key x. + See macrovariables created. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%Dict(ADD,key=x,data=18) + +%put _user_; + +%Dict(ADD,key=x,data=19) + +%put _user_; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Check for the key `x` and non existing key `t`. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%put ##%Dict(CHECK,key=x)##; +%put ##%Dict(CHECK,key=t)##; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Prints data values for various keys. + Key `t` does not exist in the macrodictionary. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%put #%Dict(FIND,key=x)#; +%put #%Dict(FIND,key=y y)#; +%put #%Dict(FIND,key=z z z)#; +%put #%Dict(FIND,key=t)#; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + List dictionary content to the log. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%Dict(LIST); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Delete keys. + Key `t` does not exist in the macrodictionary. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%put #%Dict(DEL,key=z z z)#; +%put _user_; +%put #%Dict(DEL,key=t)#; +%put _user_; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Clear and delete macro dictionary `Dict`. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%Dict(CLEAR) +%put _user_; + +%mcDictionary(Dict,DELETE) +%put _user_; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2A.** Populate macro dictionary from a dataset "by hand". + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%mcDictionary(CLASS) +%let t = %sysfunc(datetime()); +data _null_; + set sashelp.class; + call execute('%CLASS(ADD,key=' !! name !! ',data=' !! age !! ')'); +run; +%put t = %sysevalf(%sysfunc(datetime()) - &t.); +%put &=Class_KEYSNUM.; +%put _user_; +%CLASS(CLEAR) + + +%mcDictionary(CARS) +%let t = %sysfunc(datetime()); +data _null_; + set sashelp.cars(obs=42); + call execute('%CARS(ADD,key=' !! catx("|",make,model,type) !! ',data=' !! put(MPG_CITY*10,dollar10.2) !! ')'); +run; +%put t = %sysevalf(%sysfunc(datetime()) - &t.); +%put &=CARS_KEYSNUM.; +%CARS(LIST); + +%put %CARS(F,key=Audi|TT 3.2 coupe 2dr (convertible)|Sports); + +%CARS(CLEAR) +%put &=CARS_KEYSNUM.; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2B.** Populate macro dictionary from a dataset "automatically". + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%let t = %sysfunc(datetime()); +%mcDictionary(CLASS,DCL,DS=sashelp.class,k=name,d=_N_) +%put t = %sysevalf(%sysfunc(datetime()) - &t.); +%put &=CLASS_KEYSNUM.; +%put _user_; +%CLASS(CLEAR) + + +%let t = %sysfunc(datetime()); +%mcDictionary(CARS,DCL,DS=sashelp.cars(obs=42),k=catx("|",make,model,type),d=put(MPG_CITY*10,dollar10.2)) +%put t = %sysevalf(%sysfunc(datetime()) - &t.); +%put &=CARS_KEYSNUM.; +%CARS(LIST); + +%put %CARS(F,key=Audi|TT 3.2 coupe 2dr (convertible)|Sports); + +%CARS(CLEAR) +%put &=CARS_KEYSNUM.; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 3.** Data portion may require quoting and un-quoting. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%mcDictionary(CODE) +%CODE(CLEAR) +%CODE(ADD,key=data, data=%str(data test; x = 42; run;)) +%CODE(ADD,key=proc, data=%str(proc print; run;)) +%CODE(ADD,key=macro,data=%nrstr(%put *1*2*3*4*;)) + +%CODE(FIND,key=data) +%CODE(FIND,key=proc) +%unquote(%CODE(FIND,key=macro)) + +%CODE(LIST); + +%mcDictionary(CODE,DELETE) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 4.** Longer lists. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%let size = 1000; + +%mcDictionary(AAA) + +%let t = %sysfunc(datetime()); +data _null_; + do i = 1 to &size.; + call execute(cats('%AAA(ADD,key=A', i, ',data=', i, ')')); + end; +run; +%put t = %sysevalf(%sysfunc(datetime()) - &t.); +%put %AAA(F,key=A555) %AAA(CHECK,key=A555); +%put &=AAA_KEYSNUM; +%AAA(CLEAR) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 5.** Forbidden names. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%mcDictionary() +%mcDictionary(_) + +%mcDictionary(ABCDEFGHIJKLMN) %* bad; +%mcDictionary(ABCDEFGHIJKLM) %* good; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 6.** More fun with datasets. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + +data work.metadata; + input key :$16. data :$128.; +cards; +ID ABC-123-XYZ +path /path/to/study/data +cutoffDT 2023-01-01 +startDT 2020-01-01 +endDT 2024-12-31 +MedDRA v26.0 +; +run; +proc print; +run; + +%mcDictionary(Study,dcl,DS=work.metadata) + +%put _user_; + +%put *%Study(F,key=ID)**%Study(C,key=ID)*; + +title1 "Study %Study(F,key=ID) is located at %Study(F,key=path)"; +title2 "it starts %Study(F,key=startDT) and ends %Study(F,key=endDT)"; +footnote "MedDRA version: %Study(F,key=MedDRA)"; + +proc print data=sashelp.class(obs=7); +run; + +title; +footnote; + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + + +--- + +--- + +## `%mchashtable()` macro ###### + +The `%mcHashTable()` macro provided in the package +is designed to facilitate the idea of a "macro hash table" +concept, i.e. *a list of macrovariables with common prefix +and suffixes generated as a hash digest* which allows +to use values other than integers as indexes. + +The `%mcHashTable()` macro allows to generate other macros +which behaves like hash tables or dictionaries. See examples below. + +The `%mcHashTable()` macro executes like a pure macro code. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%mcHashTable( + H + <,METHOD> + <,HASH=> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `H` - *Required*, a hash table macro name and a declaration/definition, + e.g. `mcHashTable(HT)`. It names a macro which is generated by + the `%mcHashTable()` macro. Provided name cannot be empty + or an underscore (`_`). No longer than *10* characters. + +2. `METHOD` - *Optional*, if empty (or DECLARE or DCL) then the code of + a macro hash table is compiled. + If `DELETE` then the macro hash table named by `H` and all + macrovariables named like "`&H._`" are deleted. + +* `HASH=` - *Optional*, indicates which hashing algorithms should be used, + available values are `CRC32` or `MD5`, the `CRC32` is the default. + +--- + +### THE CREATED MACRO `%&H.()`: #################################################### + +The created macro imitates behaviour of a hash table or a dictionary. +It is *not* dedicated for "long-ish" lists (above 1000 elements) since +the performance may be poor. + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%&H.( + METHOD + <,KEY=> + <,DATA=> +) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `METHOD` - *Required*, indicate what behaviour should be executed. + Allowed values are: + - `ADD`, adds key and data portion to the macro hash table, + *multiple data portions* are available for one key. + - `FIND`, tests if given key exists in the macro hash table + and, if yes, returns data value associated with the key. + For multiple data portions see the `data=` parameter. + - `DP` (data portion) or `CHECK`, returns the number of data + portions for a given key. + - `CLEAR` removes all data and keys values. + - `KEYIDX`, allows to get data by the key index rather than value. + - `KEYVAL`, returns key value for a given key index. + - `CHECKIDX`, returns the number of data portions for + a given key index. + +* `KEY=` - *Optional*, provides key value for `ADD`, `FIND`,`DP`, `CHECK` + `CHECKIDX`, `KEYIDX`, and `KEYVAL` methods. Leading and trimming + spaces are removed from the value. + The `hashing(CRC32,...)` function or the `MD5(...)` function is + used to generate the hash. + +* `DATA=` - *Optional*, provides data value for the `ADD` method and + for the`FIND` method provides data portion number to be + extracted. Default value is `1` (used by the `FIND` method). + + +When macro is executed and when data are added the following types of +*global* macrovariables are created: +- `&H._########`, +- `&H._########_Xk`, +- `&H._########_Xi`, +- `&H._########_Xi_j`, +- `&H._KEYNUM`, +- and `&H._KEY_i`. + +The `#` represents value generated by the `hashing(CRC32,...)` function +or the `MD5(...)` function for the given key. + +The first type keeps information about possible collision for the key. + +The second type keeps information about value of a given key, +the `X` keeps the track of other colliding keys. + +The third type keeps information about number of data portions +for given key, the `X` keeps the track of other colliding keys. + +The fourth type keeps the data portion, the `j` indicates data portion number. + +The fifth type keeps the number of unique values of the key. + +The sixth type keeps the list of unique values of the key, +the `i` indicates key number. + +See examples below to see use cases. + +--- + +### EXAMPLES AND USECASES: #################################################### + + +**EXAMPLE 1.** Basic use-case. + Creating macro hash table, macro `HT` is generated. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%mcHashTable(HT) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Add elements to the `HT`. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%HT(ADD,key=x,data=17) +%HT(ADD,key=y,data=42) +%HT(ADD,key=z,data=303) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Add some duplicates for the key x. + See macrovariables created. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%HT(ADD,key=x,data=18) +%HT(ADD,key=x,data=19) + +%put _user_; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Check the number od data portions in macrohash + for the key `x` and non existing key `t`. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%put ##%HT(DP,key=x)##; +%put ##%HT(DP,key=t)##; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Check the number od data portions in macrohash + for the key index 1 and 4. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%put ##%HT(CHECKIDX,key=1)##; +%put ##%HT(CHECKIDX,key=4)##; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Prints first data values for various keys. + Key `t` does not exist in the macrohash. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%put #%HT(FIND,key=x)#; +%put #%HT(FIND,key=y)#; +%put #%HT(FIND,key=z)#; +%put #%HT(FIND,key=t)#; + +%put #%HT(FIND,key=x,data=2)#; +%put #%HT(FIND,key=x,data=3)#; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Print first and subsequent data values + for a given KeyIDX. Index `4` does not exist. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%put #%HT(KEYIDX,key=1)#; +%put #%HT(KEYIDX,key=2)#; +%put #%HT(KEYIDX,key=3)#; +%put #%HT(KEYIDX,key=4)#; + +%put #%HT(KEYIDX,key=1,data=2)#; +%put #%HT(KEYIDX,key=1,data=3)#; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Print the key values for a given KeyIDX. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%put #%HT(KEYVAL,key=1)#; +%put #%HT(KEYVAL,key=2)#; +%put #%HT(KEYVAL,key=3)#; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Clear and delete macro hash table `HT`. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%HT(CLEAR) +%mcHashTable(HT,DELETE) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Combine `CHECK` and `FIND` methods + with macros `%array()` and `%do_over()` + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%mcHashTable(H) +%H(ADD,key=x,data=17) +%H(ADD,key=x,data=18) +%H(ADD,key=x,data=19) + +%array(A[%H(CHECK,key=x)]); + +%put %do_over(A, phrase=%nrstr( + %H(FIND,key=x,data=&_i_) +), between = %str(,)); + +%mcHashTable(H,delete) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 3.** Populate macro hash table from a dataset. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%mcHashTable(CLASS) +%let t = %sysfunc(datetime()); +data _null_; + set sashelp.class; + call execute('%CLASS(ADD,key=' !! name !! ',data=' !! age !! ')'); + call execute('%CLASS(ADD,key=' !! name !! ',data=' !! weight !! ')'); + call execute('%CLASS(ADD,key=' !! name !! ',data=' !! height !! ')'); +run; +%put t = %sysevalf(%sysfunc(datetime()) - &t.); +%put _user_; +%CLASS(CLEAR) + + +%mcHashTable(CARS) +%let t = %sysfunc(datetime()); +data _null_; + set sashelp.cars; + call execute('%CARS(ADD,key=' !! catx("|",make,model) !! ',data=' !! MPG_CITY !! ')'); +run; +%put t = %sysevalf(%sysfunc(datetime()) - &t.); +%* %put _user_; +%CARS(CLEAR) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 4.** Data portion may require quoting and un-quoting.. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%mcHashTable(CODE) +%CODE(CLEAR) +%CODE(ADD,key=data, data=%str(data test; x = 42; run;)) +%CODE(ADD,key=proc, data=%str(proc print; run;)) +%CODE(ADD,key=macro,data=%nrstr(%put *****;)) + +%CODE(FIND,key=data) +%CODE(FIND,key=proc) +%unquote(%CODE(FIND,key=macro)) + +%mcHashTable(CODE,DELETE) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 5.** Longer lists. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%let size = 1000; + +%mcHashTable(AAA) +%mcHashTable(BBB) +%mcHashTable(CCC) +%mcHashTable(DDD) + +%let t = %sysfunc(datetime()); +data _null_; + do i = 1 to &size.; + call execute(cats('%AAA(ADD,key=A', i, ',data=', i, ')')); + end; +run; +%put t = %sysevalf(%sysfunc(datetime()) - &t.); +%put &=AAA_KEYSNUM; +%AAA(CLEAR) + +%let t = %sysfunc(datetime()); +data _null_; + do i = 1 to &size.; + call execute(cats('%BBB(ADD,key=B', i, ',data=', i, ')')); + call execute(cats('%BBB(ADD,key=B', i, ',data=', i+1, ')')); + end; +run; +%put t = %sysevalf(%sysfunc(datetime()) - &t.); +%put &=BBB_KEYSNUM; +%BBB(CLEAR) + +%let t = %sysfunc(datetime()); +data _null_; + t= datetime(); + do i = 1 to &size.; + call execute(cats('%CCC(ADD,key=C', i, ',data=', i, ')')); + end; + t = datetime() - t; + put t=; + t= datetime(); + do i = 1 to &size.; + call execute(cats('%CCC(ADD,key=C', i, ',data=', i+1, ')')); + end; + t = datetime() - t; + put t=; +run; +%put t = %sysevalf(%sysfunc(datetime()) - &t.); + +%let t = %sysfunc(datetime()); +data test; + do i = 1 to &size.; + x = resolve(cats('%CCC(FIND,key=C', i, ',data=1)')); + y = resolve(cats('%CCC(FIND,key=C', i, ',data=2)')); + output; + end; +run; +%put t = %sysevalf(%sysfunc(datetime()) - &t.); +%put &=CCC_KEYSNUM; +%CCC(CLEAR) + +%let t = %sysfunc(datetime()); +data _null_; + do i = 1 to &size.; + call execute(cats('%DDD(ADD,key=D,data=', i, ')')); + end; +run; +%put t = %sysevalf(%sysfunc(datetime()) - &t.); +%put &=DDD_KEYSNUM; +%put %DDD(CHECK,key=D); +%DDD(CLEAR) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 6.** Forbidden names. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%mcHashTable() +%mcHashTable(_) + +%mcHashTable(ABCDEFGHIJK) %* bad; +%mcHashTable(ABCDEFGHIJ) %* good; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 7.** Hashing algorithms. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%mcHashTable(H1,DCL,HASH=MD5) +%mcHashTable(H2,DECLARE,HASH=CRC32) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +--- + +## `%qziparrays()` macro ###### + +The zipArrays() and QzipArrays() macros +allow to use a function on elements of pair of +macro arrays. + +For two macroarrays the corresponding +elements are taken and the macro applies a function, provided by user, +to calculate result of the function on taken elements. + +When one of the arrays is shorter then elements are, by default, +"reused" starting from the beginning. But this behaviour can be altered. +See examples for the details. + +By default newly created macroarray name is concatenation +of first 13 characters of names of arrays used to create the new one, +e.g. if arrays names are `abc` and `def` then the result name is `abcdef`, +if arrays names are `abcd1234567890` and `efgh1234567890` then the result +name is `abcd123456789efgh123456789` + +The `zipArrays()` returns unquoted value [by `%unquote()`]. +The `QzipArrays()` returns quoted value [by `%superq()`]. + +See examples below for the details. + +The `%QzipArrays()` macro executes like a pure macro code. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%QzipArrays( + first + ,second + <,function=> + <,operator=> + <,argBf=> + <,argMd=> + <,argAf=> + <,format=> + <,result=> + <,macarray=> + <,reuse=> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `first` - *Required*, a space separated list of texts. + +2. `second` - *Required*, a space separated list of texts. + +* `function = cat` - *Optional*, default value is `cat`, + a function which will be applied + to corresponding pairs of elements of + the first and the second list. + +* `operator =` - *Optional*, default value is empty, + arithmetic infix operator used with elements + the first and the second list. The first + list is used on the left side of the operator + the second list is used on the right side + of the operator. + +* `argBf =` - *Optional*, default value is empty, + arguments of the function inserted + *before* elements the first list. + If multiple should be comma separated. + +* `argMd =` - *Optional*, default value is empty, + arguments of the function inserted + *between* elements the first list and + the second list. + If multiple should be comma separated. + +* `argAf =` - *Optional*, default value is empty, + arguments of the function inserted + *after* elements the second list. + If multiple should be comma separated. + +* `format=` - *Optional*, default value is empty, + indicates a format which should be used + to format the result, does not work when + the `operator=` is used. + +* `result=` - *Optional*, default value is empty, + indicates a name of newly created macroarray, + by default created macroarray name is concatenation + of first 13 characters of names of arrays used + to create the new one. + +* `macarray=N` - *Optional*, default value is `N`, + if set to `Y`/`YES` then a macro, named with + the array name, is compiled to create convenient + envelope for multiple ampersands, see the + `%array()` macro for details. + +* `reuse=Y` - *Optional*, default value is `Y`, + when one of the arrays is shorter then elements + are *reused* starting from the beginning. + If `CP` then function is executed on the *Cartesian + product* of arrays elements. Any other value will + cut the process with the end of the shorter array. + See examples for the details. + + +### EXAMPLES AND USECASES: #################################################### + +See examples in `%zipArrays()` help for the details. + +--- + +--- + +## `%sortmacroarray()` macro ###### + +The sortMacroArray() macro +allow to sort elements of a macro array. + +The **limitation** is that sorted values are limited to 32767 bytes of length. + +See examples below for the details. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%sortMacroArray( + array + <,valLength=> + <,outSet=> + <,sortseq=> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `array` - *Required*, name of an array generated by the `%array()` macro. + +* `valLength = 32767` - *Optional*, default value is `32767`, + maximum length of a variable storing macrovariable data. + (the reason of 32767 limitation) + +* `outSet = _NULL_` - *Optional*, default value is `_NULL_`, + an optional output dataset name. + +* `sortseq =` - *Optional*, default value is `LINGUISTIC(NUMERIC_COLLATION = ON)`, + sorting options for use in an internal `Proc SORT`. + + +### EXAMPLES AND USECASES: #################################################### + + +**EXAMPLE 1.** Basic use-case. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + +options mprint; +ods html; +ods listing close; + + +%array(hij [4:9] $ 512 ("C33" "B22" "A11" "A01" "A02" "X42"), macarray=Y) + +%put NOTE: %do_over(hij); + +%sortMacroArray(hij, valLength=3, outSet = A_NULL_(compress=char)) + +%put NOTE: %do_over(hij); + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Basic use-case. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas + +options mprint; +ods html; +ods listing close; + + +%array(ds = sashelp.class, vars = name|NNN height|h, macarray=Y) +%array(ds = sashelp.cars, vars = model|, macarray=Y) + +%put NOTE: %do_over(NNN); +%put NOTE: %do_over(H); +%put NOTE: %do_over(model); + +%sortMacroArray(NNN, valLength=30, outSet = A_NULL_(compress=char)) +%sortMacroArray(H, valLength=32) +%sortMacroArray(model, valLength=120) + +%put NOTE: %do_over(NNN); +%put NOTE: %do_over(H); +%put NOTE: %do_over(model); + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + + +--- + +## `%ziparrays()` macro ###### + +The zipArrays() and QzipArrays() macros +allow to use a function on elements of pair of +macro arrays. + +For two macroarrays the corresponding +elements are taken and the macro applies a function, provided by user, +to calculate result of the function on taken elements. + +When one of the arrays is shorter then elements are, by default, +"reused" starting from the beginning. But this behaviour can be altered. +See examples for the details. + +By default newly created macroarray name is concatenation +of first 13 characters of names of arrays used to create the new one, +e.g. if arrays names are `abc` and `def` then the result name is `abcdef`, +if arrays names are `abcd1234567890` and `efgh1234567890` then the result +name is `abcd123456789efgh123456789` + +The `zipArrays()` returns unquoted value [by `%unquote()`]. +The `QzipArrays()` returns quoted value [by `%superq()`]. + +See examples below for the details. + +The `%zipArrays()` macro executes like a pure macro code. + +### SYNTAX: ################################################################### + +The basic syntax is the following, the `<...>` means optional parameters: +~~~~~~~~~~~~~~~~~~~~~~~sas +%zipArrays( + first + ,second + <,function=> + <,operator=> + <,argBf=> + <,argMd=> + <,argAf=> + <,format=> + <,result=> + <,macarray=> + <,reuse=> +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `first` - *Required*, a space separated list of texts. + +2. `second` - *Required*, a space separated list of texts. + +* `function = cat` - *Optional*, default value is `cat`, + a function which will be applied + to corresponding pairs of elements of + the first and the second list. + +* `operator =` - *Optional*, default value is empty, + arithmetic infix operator used with elements + the first and the second list. The first + list is used on the left side of the operator + the second list is used on the right side + of the operator. + +* `argBf =` - *Optional*, default value is empty, + arguments of the function inserted + *before* elements the first list. + If multiple should be comma separated. + +* `argMd =` - *Optional*, default value is empty, + arguments of the function inserted + *between* elements the first list and + the second list. + If multiple should be comma separated. + +* `argAf =` - *Optional*, default value is empty, + arguments of the function inserted + *after* elements the second list. + If multiple should be comma separated. + +* `format=` - *Optional*, default value is empty, + indicates a format which should be used + to format the result, does not work when + the `operator=` is used. + +* `result=` - *Optional*, default value is empty, + indicates a name of newly created macroarray, + by default created macroarray name is concatenation + of first 13 characters of names of arrays used + to create the new one. + +* `macarray=N` - *Optional*, default value is `N`, + if set to `Y`/`YES` then a macro, named with + the array name, is compiled to create convenient + envelope for multiple ampersands, see the + `%array()` macro for details. + +* `reuse=Y` - *Optional*, default value is `Y`, + when one of the arrays is shorter then elements + are *reused* starting from the beginning. + If `CP` then function is executed on the *Cartesian + product* of arrays elements. Any other value will + cut the process with the end of the shorter array. + See examples for the details. + + +### EXAMPLES AND USECASES: #################################################### + +**EXAMPLE 1.** Simple concatenation of elements: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%array(a[*] x1-x3 (1:3)) +%array(b[*] x1-x5 (11:15)) + +%put _user_; + +%zipArrays(a, b); +%put _user_; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 2.** Shorter list is "reused": +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%array(a[6] (1:6)) +%array(b[3] (10 20 30)) + +%zipArrays(a, b, result=A_and_B, macarray=Y); +%put %do_over(A_and_B); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 3.** Use of the `operator=`: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%array(c[0:4] (000 100 200 300 400)) +%array(d[2:16] (1002:1016)) + +%zipArrays(c, d, operator=+, result=C_plus_D, macarray=Y); +%put (%do_over(C_plus_D)); + +%put %C_plus_D(1); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 4.** If one of array names is empty or an array does not exist: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%array(a[6] (1:6)) +%array(b[3] (10 20 30)) + +%zipArrays(a, ); +%zipArrays(, b); + +%zipArrays(a, z); +%zipArrays(z, b); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 5.** Use of the `function=`: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%array(one[3] A B C, vnames=Y) +%array(two[5] p q r s t, vnames=Y) + +%zipArrays( + one +,two +,function = catx +,argBf = %str( ) +,format = $quote. +,macarray=Y +) +%put %do_over(onetwo); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 6.** To reuse or not to reuse, or maybe Cartesian product: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%array(e[3] (10 20 30)) +%array(f[2] (5:6)) + +%zipArrays(e, f, reuse=n, operator=+, macarray=Y, result=_noReuse); +%zipArrays(e, f, reuse=y, operator=+, macarray=Y, result=_yesReuse); +%zipArrays(e, f, reuse=cp, operator=+, macarray=Y, result=_cartProdReuse); + +%put %do_over(_noReuse); +%put %do_over(_yesReuse); +%put %do_over(_cartProdReuse); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +**EXAMPLE 7.** Use middle argument: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%array(yr[3] (2018:2020)) +%array(mth[12] (1:12)) + +%zipArrays(mth, yr, argMd=5, function=MDY, format=date11., macarray=Y); +%put %do_over(mthyr); + +%zipArrays(mth, yr, argMd=5, function=MDY, format=date11., macarray=Y, reuse=cp); +%put %do_over(mthyr); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +--- + + +--- + +# License ###### + +Copyright (c) Bartosz Jablonski, 2019 - 2026 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + diff --git a/hist/macroarray_1.3.2_.zip b/hist/macroarray_1.3.2_.zip new file mode 100644 index 0000000000000000000000000000000000000000..f43dc3ff9778b95003880ed8595380b4980a659e GIT binary patch literal 56893 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%0AS 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 literal 0 HcmV?d00001 diff --git a/macroarray.md b/macroarray.md index 9aff59d..9b5446c 100644 --- a/macroarray.md +++ b/macroarray.md @@ -9,17 +9,17 @@ ### Version information: - Package: macroArray -- Version: 1.3.1 -- Generated: 2026-01-26T15:33:03 +- Version: 1.3.2 +- Generated: 2026-02-17T08:51:01 - Author(s): Bartosz Jablonski (yabwon@gmail.com) - Maintainer(s): Bartosz Jablonski (yabwon@gmail.com) - License: MIT -- File SHA256: `F*9DA64CA9A745E1DB7176F7AF4459BB014F61F71626473ABF6471A32689E14FF1` for this version -- Content SHA256: `C*15A52658C8CBF9AB36AB1CA847FA628CCC6E9C67F625FFD3A959EB191445F780` for this version +- File SHA256: `F*35A657517CD2B1AB86C4E7C5320B5EDDDFBA9348075AE31DDAF875CF0CC193C9` for this version +- Content SHA256: `C*DE477F4E280D438B364320F324C88DA3D336F102BA37810C60BDE15398DE84E9` for this version --- -# The `macroArray` package, version: `1.3.1`; +# The `macroArray` package, version: `1.3.2`; --- @@ -43,6 +43,14 @@ Some of components are: - `%mcDictionary()`, - etc. +Read this article to learn more: +"Macro Variable Arrays Made Easy with macroArray SAS Package" + +Link to the text: +`https://www.lexjansen.com/pharmasug/2024/AP/PharmaSUG-2024-AP-108.pdf` +or +`https://www.lexjansen.com/wuss/2024/124_FINAL_paper_pdf.pdf` + *Note:* If you are working with BIG macroarrays do not forget to verify your session setting for macro @@ -75,7 +83,7 @@ Required SAS Components: --------------------------------------------------------------------- -*SAS package generated by SAS Package Framework, version `20260126`,* +*SAS package generated by SAS Package Framework, version `20260216`,* *under `WIN`(`X64_10PRO`) operating system,* *using SAS release: `9.04.01M9P06042025`.* diff --git a/macroarray.zip b/macroarray.zip index 2bdaf63744fa7f38003c19e9438ccbebef7e9c0f..f43dc3ff9778b95003880ed8595380b4980a659e 100644 GIT binary patch delta 10704 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 delta 10400 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