diff --git a/README.md b/README.md
index a029883..ccde8e5 100644
--- a/README.md
+++ b/README.md
@@ -122,7 +122,7 @@ SHA256 digest for DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB8
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
-- **macroArray**\[0.9\], implementation of an array concept in a macrolanguage, e.g.
+- **macroArray**\[1.0\], implementation of an array concept in a macrolanguage, e.g.
```sas
%array(ABC[17] (111:127), macarray=Y);
@@ -141,7 +141,7 @@ SHA256 digest for DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB8
which = 1:H:2
);
```
-SHA256 digest for macroArray: 833D747526F4CE83FFD73F9EB3A2A9065401B498DFEC79045A28A42E0E57A8CA
+SHA256 digest for macroArray: DAEB87654D99965BF2B7A6AB14626B3E617D0ABF526E77725DF89A1AB4C812C2
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
diff --git a/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf b/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf
index fdd9ff6..0d7f963 100644
Binary files a/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf and b/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf differ
diff --git a/SPF/Documentation/SAS(r) packages - the way to share (a how to)- Paper 4725-2020 - extended.pdf b/SPF/Documentation/SAS(r) packages - the way to share (a how to)- Paper 4725-2020 - extended.pdf
index 797df12..440a26b 100644
Binary files a/SPF/Documentation/SAS(r) packages - the way to share (a how to)- Paper 4725-2020 - extended.pdf and b/SPF/Documentation/SAS(r) packages - the way to share (a how to)- Paper 4725-2020 - extended.pdf differ
diff --git a/packages/README.md b/packages/README.md
index 95c101a..3979684 100644
--- a/packages/README.md
+++ b/packages/README.md
@@ -65,7 +65,7 @@ SHA256 digest for DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB8
---
-- **macroArray**\[0.9\], implementation of an array concept in a macro language, e.g.
+- **macroArray**\[1.0\], implementation of an array concept in a macro language, e.g.
```sas
%array(ABC[17] (111:127), macarray=Y);
@@ -84,7 +84,7 @@ SHA256 digest for DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB8
which = 1:H:2
);
```
-SHA256 digest for macroArray: 833D747526F4CE83FFD73F9EB3A2A9065401B498DFEC79045A28A42E0E57A8CA
+SHA256 digest for macroArray: DAEB87654D99965BF2B7A6AB14626B3E617D0ABF526E77725DF89A1AB4C812C2
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
diff --git a/packages/SHA256_for_packages.txt b/packages/SHA256_for_packages.txt
index 25f2fe9..0b139a9 100644
--- a/packages/SHA256_for_packages.txt
+++ b/packages/SHA256_for_packages.txt
@@ -1,3 +1,6 @@
+/* 20220217 */
+macroArray: DAEB87654D99965BF2B7A6AB14626B3E617D0ABF526E77725DF89A1AB4C812C2
+
/* 20220113 */
BasePlus: A60A300E083628C65DD6899E7EF95588916F8F66B6A25B32B3228987B6F74857
DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB81444ABB
diff --git a/packages/macroarray.md b/packages/macroarray.md
index a91cc99..a26f489 100644
--- a/packages/macroarray.md
+++ b/packages/macroarray.md
@@ -10,6 +10,7 @@
* [`%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)
@@ -18,7 +19,7 @@
---
-# The macroArray package [ver. 0.9] ###############################################
+# The macroArray package [ver. 1.0] ###############################################
The **macroArray** package implements a macro array facility:
- `%array()`,
@@ -30,6 +31,7 @@ The **macroArray** package implements a macro array facility:
- `%mcHashTable()`,
- `%zipArrays()`,
- `%sortMacroArray()`,
+- `%mcDictionary()`,
- etc.
The set of macros, which emulates classic
@@ -64,10 +66,11 @@ Package contains:
7. macro do_over2
8. macro do_over3
9. macro make_do_over
- 10. macro mchashtable
- 11. macro sortmacroarray
- 12. macro qziparrays
- 13. macro ziparrays
+ 10. macro mcdictionary
+ 11. macro mchashtable
+ 12. macro qziparrays
+ 13. macro sortmacroarray
+ 14. macro ziparrays
Required SAS Components:
*Base SAS Software*
@@ -75,7 +78,7 @@ Required SAS Components:
*SAS package generated by generatePackage, version 20220113.*
The SHA256 hash digest for package macroArray:
-`833D747526F4CE83FFD73F9EB3A2A9065401B498DFEC79045A28A42E0E57A8CA`
+`DAEB87654D99965BF2B7A6AB14626B3E617D0ABF526E77725DF89A1AB4C812C2`
---
# Content description ############################################################################################
@@ -1210,7 +1213,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
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.
+ available values are `CRC32` or `MD5`, the `CRC32` is the default.
---
@@ -1391,7 +1394,7 @@ See examples below to see use cases.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-**EXAMPLE 2.** Populate macro hash table from a dataset.
+**EXAMPLE 3.** Populate macro hash table from a dataset.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcHashTable(CLASS)
@@ -1419,7 +1422,7 @@ run;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-**EXAMPLE 3.** Data portion may require quoting and un-quoting..
+**EXAMPLE 4.** Data portion may require quoting and un-quoting..
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcHashTable(CODE)
@@ -1436,7 +1439,7 @@ run;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-**EXAMPLE 4.** Longer lists.
+**EXAMPLE 5.** Longer lists.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%let size = 1000;
@@ -1509,7 +1512,7 @@ run;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-**EXAMPLE 5.** Forbidden names.
+**EXAMPLE 6.** Forbidden names.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcHashTable()
@@ -1519,7 +1522,7 @@ run;
%mcHashTable(ABCDEFGHIJKLMNOP) %* good;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-**EXAMPLE 5.** Hashing algorithms.
+**EXAMPLE 7.** Hashing algorithms.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
%mcHashTable(H1,DCL,HASH=MD5)
@@ -1528,6 +1531,252 @@ run;
---
+## >>> `%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>
+)
+~~~~~~~~~~~~~~~~~~~~~~~
+
+**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.
+
+---
+
+### 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 2.** Populate macro dictionary from a dataset.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~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 _user_;
+%CLASS(CLEAR)
+
+
+%mcDictionary(CARS)
+%let t = %sysfunc(datetime());
+data _null_;
+ set sashelp.cars;
+ call execute('%CARS(ADD,key=' !! catx("|",make,model,type) !! ',data=' !! MPG_CITY !! ')');
+run;
+%put t = %sysevalf(%sysfunc(datetime()) - &t.);
+%put &=CARS_KEYSNUM.;
+%CARS(LIST);
+%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 *****;))
+
+%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_KEYSNUM;
+%AAA(CLEAR)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+**EXAMPLE 5.** Forbidden names.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
+%mcDictionary()
+%mcDictionary(_)
+
+%mcDictionary(ABCDEFGHIJKLMNOPQ) %* bad;
+%mcDictionary(ABCDEFGHIJKLMNOP) %* good;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+---
+
## >>> `%QzipArrays()` macro: <<< #######################
The zipArrays() and QzipArrays() macros
diff --git a/packages/macroarray.zip b/packages/macroarray.zip
index fae73f3..837bca5 100644
Binary files a/packages/macroarray.zip and b/packages/macroarray.zip differ