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:
yabwon
2020-10-23 10:34:20 +02:00
parent 2730a9438f
commit 4eaa1e63ec
5 changed files with 379 additions and 18 deletions

View File

@@ -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