From 8c6b5e4b25dc22dc24eb08f0f5bd717e4755a52e Mon Sep 17 00:00:00 2001 From: Bart Jablonski Date: Thu, 23 Nov 2023 21:51:14 +0100 Subject: [PATCH] The macroArray package [ver. 1.2.3] ## The macroArray package [ver. 1.2.3] - Update in `q=` parameter for the `%array()` macro. - Fix in data set existence for `ds=` parameter in the `%array()` macro. - Documentation updated. --- SHA256 digests for packages: - macroArray: `F*A0840B92EB9356EDB318DBE9B579A345C85ABF69E8D5F7C73C144C66F2F74FB4` --- README.md | 2 +- hist/1.2.3/macroarray.md | 2286 +++++++++++++++++++++++++++++++++++++ hist/1.2.3/macroarray.zip | Bin 0 -> 53337 bytes macroarray.md | 21 +- macroarray.zip | Bin 53233 -> 53337 bytes 5 files changed, 2298 insertions(+), 11 deletions(-) create mode 100644 hist/1.2.3/macroarray.md create mode 100644 hist/1.2.3/macroarray.zip diff --git a/README.md b/README.md index 25817e8..6e647ca 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*2A108D121D4DACAA8752E681301371F80F0500B2EE28A9E3B39678415BCBD6B2 +SHA256 digest for the latest version of `macroArray`: F*A0840B92EB9356EDB318DBE9B579A345C85ABF69E8D5F7C73C144C66F2F74FB4 [**Documentation for macroArray**](./macroarray.md "Documentation for macroArray") diff --git a/hist/1.2.3/macroarray.md b/hist/1.2.3/macroarray.md new file mode 100644 index 0000000..8f6b1b4 --- /dev/null +++ b/hist/1.2.3/macroarray.md @@ -0,0 +1,2286 @@ +- [The macroArray package](#macroarray) +- [Content description](#content-description) + * [`%appendArray()` macro](#appendarray-macro) + * [`%appendCell()` macro](#appendcell-macro) + * [`%array()` macro](#array-macro) + * [`%concatArrays()` macro](#concatarrays-macro) + * [`%deleteMacArray()` macro](#deletemacarray-macro) + * [`%do_over()` macro](#do-over-macro) + * [`%do_over2()` macro](#do-over2-macro) + * [`%do_over3()` macro](#do-over3-macro) + * [`%make_do_over()` macro](#make-do-over-macro) + * [`%mcHashTable()` macro](#mchashtable-macro) + * [`%mcDictionary()` macro](#mcdictionary-macro) + * [`%QzipArrays()` macro](#qziparrays-macro) + * [`%zipArrays()` macro](#ziparrays-macro) + * [`%sortMacroArray()` macro](#sortmacroarray-macro) + + * [License](#license) + +--- + +# The macroArray package [ver. 1.2.3] ############################################### + +The **macroArray** package implements a macroarray facility: +- `%array()`, +- `%do_over()`, +- `%make_do_over()`, +- `%deletemacarray()`, +- `%concatarrays()`, +- `%appendcell()`, +- `%mcHashTable()`, +- `%zipArrays()`, +- `%sortMacroArray()`, +- `%mcDictionary()`, +- etc. + +The set of macros, which emulates classic +data-step-array functionality on the macro +programming level, is provided. + +*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. | + +--- + +Package contains: + 1. macro appendarray + 2. macro appendcell + 3. macro array + 4. macro concatarrays + 5. macro deletemacarray + 6. macro do_over + 7. macro do_over2 + 8. macro do_over3 + 9. macro make_do_over + 10. macro mcdictionary + 11. macro mchashtable + 12. macro qziparrays + 13. macro sortmacroarray + 14. macro ziparrays + +Required SAS Components: + *Base SAS Software* + +*SAS package generated by generatePackage, version 20231123* + +The SHA256 hash digest for package macroArray: +`F*A0840B92EB9356EDB318DBE9B579A345C85ABF69E8D5F7C73C144C66F2F74FB4` + +--- +# Content description ############################################################################################ + +## >>> `%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( + array + <,phrase=%nrstr(%&array(&_I_.))> + <,between=%str( )> + <,which = > +) +~~~~~~~~~~~~~~~~~~~~~~~ + +**Arguments description**: + +1. `array` - *Required*, indicates a macroarray which metadata (Lbound, Hbouns) + are to be 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. + + + +### 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 + , phrase = %NRSTR(%alpha(&_I_.)) + , 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(,))#; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--- + + + +## >>> `%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_.)) + ) + ); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +--- + +## >>> `%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 *16* 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(ABCDEFGHIJKLMNOPQ) %* bad; +%mcHashTable(ABCDEFGHIJKLMNOP) %* good; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**EXAMPLE 7.** Hashing algorithms. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas +%mcHashTable(H1,DCL,HASH=MD5) +%mcHashTable(H2,DECLARE,HASH=CRC32) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `%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 *16* 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(ABCDEFGHIJKLMNOPQ) %* bad; +%mcDictionary(ABCDEFGHIJKLMNOP) %* 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; + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `%QzipArrays()` macro: <<< ####################### + +The zipArrays() and QzipArrays() macros +allow to use a function on elements of pair of +macroarrays. + +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. + +--- + +## >>> `%zipArrays()` macro: <<< ####################### + +The zipArrays() and QzipArrays() macros +allow to use a function on elements of pair of +macroarrays. + +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); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## >>> `%sortMacroArray()` macro: <<< ####################### + +The sortMacroArray() macro +allow to sort elements of a macroarray. + +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); + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +--- + +## License #################################################################### + +Copyright (c) Bartosz Jablonski, since January 2019 + +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/1.2.3/macroarray.zip b/hist/1.2.3/macroarray.zip new file mode 100644 index 0000000000000000000000000000000000000000..81f014dc51d6c5d54e6ce1d210ad3bde6e3a4da9 GIT binary patch literal 53337 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 Fmv}kq6hF=1y~=&(pg`if^ax3{^F4>aw0SbtyoI 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 bhJs}d@!l$+VzRW&$x7%A*p ############################################### +# The macroArray package [ver. 1.2.3] ############################################### -The **macroArray** package implements a macro array facility: +The **macroArray** package implements a macroarray facility: - `%array()`, - `%do_over()`, - `%make_do_over()`, @@ -75,10 +75,10 @@ Package contains: Required SAS Components: *Base SAS Software* -*SAS package generated by generatePackage, version 20231111* +*SAS package generated by generatePackage, version 20231123* The SHA256 hash digest for package macroArray: -`F*2A108D121D4DACAA8752E681301371F80F0500B2EE28A9E3B39678415BCBD6B2` +`F*A0840B92EB9356EDB318DBE9B579A345C85ABF69E8D5F7C73C144C66F2F74FB4` --- # Content description ############################################################################################ @@ -244,7 +244,7 @@ The code of a macro was inspired by The `%array()` macro version provided in the package is designed to facilitate -the idea of macro array concept, i.e. *a list of +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. @@ -253,7 +253,7 @@ 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 macro arrays out + 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 @@ -346,8 +346,9 @@ The basic syntax is the following, the `<...>` means optional parameters: 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`) if the value be surrounded by quotes. +* `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`. @@ -1867,7 +1868,7 @@ footnote; The zipArrays() and QzipArrays() macros allow to use a function on elements of pair of -macro arrays. +macroarrays. For two macroarrays the corresponding elements are taken and the macro applies a function, provided by user, @@ -1978,7 +1979,7 @@ See examples in `%zipArrays()` help for the details. The zipArrays() and QzipArrays() macros allow to use a function on elements of pair of -macro arrays. +macroarrays. For two macroarrays the corresponding elements are taken and the macro applies a function, provided by user, @@ -2177,7 +2178,7 @@ The basic syntax is the following, the `<...>` means optional parameters: ## >>> `%sortMacroArray()` macro: <<< ####################### The sortMacroArray() macro -allow to sort elements of a macro array. +allow to sort elements of a macroarray. The **limitation** is that sorted values are limited to 32767 bytes of length. diff --git a/macroarray.zip b/macroarray.zip index 97b3c3e50229d6f09fc72055f44cc2e0461e39ad..81f014dc51d6c5d54e6ce1d210ad3bde6e3a4da9 100644 GIT binary patch delta 16630 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