mirror of
https://github.com/yabwon/SAS_PACKAGES.git
synced 2026-01-03 13:20:05 +00:00
macroArray, version 0.7:
macroArray, version 0.7: The `%mcHashTable()` macro was added in the package. It 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.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
- [The macroArray package [ver. 0.6]](#macroarray)
|
||||
- [The macroArray package](#macroarray)
|
||||
- [Content description](#content-description)
|
||||
* [`%appendArray()` macro](#appendarray-macro)
|
||||
* [`%appendCell()` macro](#appendcell-macro)
|
||||
@@ -9,11 +9,12 @@
|
||||
* [`%do_over2()` macro](#do-over2-macro)
|
||||
* [`%do_over3()` macro](#do-over3-macro)
|
||||
* [`%make_do_over()` macro](#make-do-over-macro)
|
||||
* [`%mcHashTable()` macro](#mchashtable-macro)
|
||||
* [License](#license)
|
||||
|
||||
---
|
||||
|
||||
# The macroArray package [ver. 0.6] <a name="macroarray-package"></a> ###############################################
|
||||
# The macroArray package [ver. 0.7] <a name="macroarray-package"></a> ###############################################
|
||||
|
||||
The **macroArray** package implements a macro array facility:
|
||||
- `%array()`,
|
||||
@@ -21,7 +22,8 @@ The **macroArray** package implements a macro array facility:
|
||||
- `%make_do_over()`,
|
||||
- `%deletemacarray()`,
|
||||
- `%concatarrays()`,
|
||||
- `%appendcell()`.
|
||||
- `%appendcell()`,
|
||||
- `%mcHashTable()`,
|
||||
- etc.
|
||||
|
||||
The set of macros, which emulates classic
|
||||
@@ -47,23 +49,24 @@ to verify the following options:
|
||||
---
|
||||
|
||||
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
|
||||
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 mchashtable
|
||||
|
||||
Required SAS Components:
|
||||
*Base SAS Software*
|
||||
|
||||
*SAS package generated by generatePackage, version 20200911*
|
||||
*SAS package generated by generatePackage, version 20201018.*
|
||||
|
||||
The SHA256 hash digest for package macroArray:
|
||||
`42771AA7CD2A0608E1EE25F104F21CCCC296919910E4BCA7AD9AE46A291BB8D7`
|
||||
`75056F508E96296DC50096BBB054C58334DB913AD37885958099EDCE0C330CB2`
|
||||
|
||||
---
|
||||
# Content description ############################################################################################
|
||||
@@ -1161,6 +1164,361 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---
|
||||
|
||||
## >>> `%mcHashTable()` macro: <<< <a name="mchashtable-macro"></a> #######################
|
||||
|
||||
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 2.** 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 3.** 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 4.** 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 5.** Forbidden names.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%mcHashTable()
|
||||
%mcHashTable(_)
|
||||
|
||||
%mcHashTable(ABCDEFGHIJKLMNOPQ) %* bad;
|
||||
%mcHashTable(ABCDEFGHIJKLMNOP) %* good;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**EXAMPLE 5.** Hashing algorithms.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%mcHashTable(H1,DCL,HASH=MD5)
|
||||
%mcHashTable(H2,DECLARE,HASH=CRC32)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
---
|
||||
|
||||
## License ####################################################################
|
||||
|
||||
Copyright (c) Bartosz Jablonski, since January 2019
|
||||
|
||||
Reference in New Issue
Block a user