diff --git a/README.md b/README.md
index e11f80f..942468e 100644
--- a/README.md
+++ b/README.md
@@ -116,7 +116,7 @@ SHA256 digest for DFA: 1FC8D030D576C33F1B5DEB27E17534946209BC148D57A1357CA025ED1
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
-- **macroArray**\[0.7\], implementation of an array concept in a macrolanguage, e.g.
+- **macroArray**\[0.8\], implementation of an array concept in a macrolanguage, e.g.
```
%array(ABC[17] (111:127), macarray=Y);
@@ -135,12 +135,12 @@ SHA256 digest for DFA: 1FC8D030D576C33F1B5DEB27E17534946209BC148D57A1357CA025ED1
which = 1:H:2
);
```
-SHA256 digest for macroArray: 0F1B985E2FC34C91D2A3BD237DC294502A76913B71266D76702A5E77A78C9CA7
+SHA256 digest for macroArray: AC3AD58AFBBE459616743DC6346330BD8DD33FBA8CDD595423F181B67D0475BC
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
-- **BasePlus**\[0.99\] adds a bunch of functionalities I am missing in BASE SAS, such as:
+- **BasePlus**\[0.991\] adds a bunch of functionalities I am missing in BASE SAS, such as:
```
call arrMissToRight(myArray);
call arrFillMiss(17, myArray);
@@ -154,7 +154,7 @@ format x bool.;
%put %getVars(sashelp.class, pattern = ght$, sep = +, varRange = _numeric_);
```
-SHA256 digest for BasePlus: 7933E6BCFDCA7C04EAAC537773574799759007A5D2AED639E86CF4EA631F1351
+SHA256 digest for BasePlus: 9EA40F72191D1916189F043315CA519F6E42CEB05C186F7653AE464D21D21CFB
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
diff --git a/packages/README.md b/packages/README.md
index e2d3a10..68a2181 100644
--- a/packages/README.md
+++ b/packages/README.md
@@ -65,7 +65,7 @@ SHA256 digest for DFA: 1FC8D030D576C33F1B5DEB27E17534946209BC148D57A1357CA025ED1
---
-- **macroArray**\[0.7\], implementation of an array concept in a macro language, e.g.
+- **macroArray**\[0.8\], implementation of an array concept in a macro language, e.g.
```
%array(ABC[17] (111:127), macarray=Y);
@@ -84,13 +84,13 @@ SHA256 digest for DFA: 1FC8D030D576C33F1B5DEB27E17534946209BC148D57A1357CA025ED1
which = 1:H:2
);
```
-SHA256 digest for macroArray: 0F1B985E2FC34C91D2A3BD237DC294502A76913B71266D76702A5E77A78C9CA7
+SHA256 digest for macroArray: AC3AD58AFBBE459616743DC6346330BD8DD33FBA8CDD595423F181B67D0475BC
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
---
-- **BasePlus**\[0.99\] adds a bunch of functionalities I am missing in BASE SAS, such as:
+- **BasePlus**\[0.991\] adds a bunch of functionalities I am missing in BASE SAS, such as:
```
call arrMissToRight(myArray);
call arrFillMiss(17, myArray);
@@ -104,7 +104,7 @@ format x bool.;
%put %getVars(sashelp.class, pattern = ght$, sep = +, varRange = _numeric_);
```
-SHA256 digest for BasePlus: 7933E6BCFDCA7C04EAAC537773574799759007A5D2AED639E86CF4EA631F1351
+SHA256 digest for BasePlus: 9EA40F72191D1916189F043315CA519F6E42CEB05C186F7653AE464D21D21CFB
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
diff --git a/packages/SHA256_for_packages.txt b/packages/SHA256_for_packages.txt
index 1a8208a..da870e5 100644
--- a/packages/SHA256_for_packages.txt
+++ b/packages/SHA256_for_packages.txt
@@ -1,3 +1,7 @@
+/* 20201207 */
+macroArray: AC3AD58AFBBE459616743DC6346330BD8DD33FBA8CDD595423F181B67D0475BC
+BasePlus: 9EA40F72191D1916189F043315CA519F6E42CEB05C186F7653AE464D21D21CFB
+
/* 20201202 */
BasePlus: 7933E6BCFDCA7C04EAAC537773574799759007A5D2AED639E86CF4EA631F1351
diff --git a/packages/baseplus.md b/packages/baseplus.md
index c4989e8..afe3ef4 100644
--- a/packages/baseplus.md
+++ b/packages/baseplus.md
@@ -46,7 +46,7 @@
---
-# The BasePlus package [ver. 0.99] ###############################################
+# The BasePlus package [ver. 0.991] ###############################################
The **BasePlus** package implements useful
functions and functionalities I miss in the BASE SAS.
@@ -224,7 +224,7 @@ Package contains:
*SAS package generated by generatePackage, version 20201115*
The SHA256 hash digest for package BasePlus:
-`7933E6BCFDCA7C04EAAC537773574799759007A5D2AED639E86CF4EA631F1351`
+`9EA40F72191D1916189F043315CA519F6E42CEB05C186F7653AE464D21D21CFB`
---
# Content description ############################################################################################
diff --git a/packages/baseplus.zip b/packages/baseplus.zip
index 94c186a..fa90c57 100644
Binary files a/packages/baseplus.zip and b/packages/baseplus.zip differ
diff --git a/packages/macroarray.md b/packages/macroarray.md
index 353b258..c55a304 100644
--- a/packages/macroarray.md
+++ b/packages/macroarray.md
@@ -10,11 +10,13 @@
* [`%do_over3()` macro](#do-over3-macro)
* [`%make_do_over()` macro](#make-do-over-macro)
* [`%mcHashTable()` macro](#mchashtable-macro)
+ * [`%QzipArrays()` macro](#qziparrays-macro)
+ * [`%zipArrays()` macro](#ziparrays-macro)
* [License](#license)
---
-# The macroArray package [ver. 0.7] ###############################################
+# The macroArray package [ver. 0.8] ###############################################
The **macroArray** package implements a macro array facility:
- `%array()`,
@@ -24,6 +26,7 @@ The **macroArray** package implements a macro array facility:
- `%concatarrays()`,
- `%appendcell()`,
- `%mcHashTable()`,
+- `%zipArrays()`,
- etc.
The set of macros, which emulates classic
@@ -66,7 +69,7 @@ Required SAS Components:
*SAS package generated by generatePackage, version 20201115.*
The SHA256 hash digest for package macroArray:
-`0F1B985E2FC34C91D2A3BD237DC294502A76913B71266D76702A5E77A78C9CA7`
+`AC3AD58AFBBE459616743DC6346330BD8DD33FBA8CDD595423F181B67D0475BC`
---
# Content description ############################################################################################
@@ -1519,6 +1522,317 @@ run;
---
+## >>> `%QzipArrays()` macro: <<< #######################
+
+The zipArrays() and QzipArrays() macros
+allow to use a function on elements of pair of
+macro arrays.
+
+For two macroarrays the corresponding
+elements are taken and the macro applies a function, provided by user,
+to calculate result of the function on taken elements.
+
+When one of the arrays is shorter then elements are, by default,
+"reused" starting from the beginning. But this behaviour can be altered.
+See examples for the details.
+
+By default newly created macroarray name is concatenation
+of first 13 characters of names of arrays used to create the new one,
+e.g. if arrays names are `abc` and `def` then the result name is `abcdef`,
+if arrays names are `abcd1234567890` and `efgh1234567890` then the result
+name is `abcd123456789efgh123456789`
+
+The `zipArrays()` returns unquoted value [by `%unquote()`].
+The `QzipArrays()` returns quoted value [by `%superq()`].
+
+See examples below for the details.
+
+The `%QzipArrays()` macro executes like a pure macro code.
+
+### SYNTAX: ###################################################################
+
+The basic syntax is the following, the `<...>` means optional parameters:
+~~~~~~~~~~~~~~~~~~~~~~~sas
+%QzipArrays(
+ first
+ ,second
+ <,function=>
+ <,operator=>
+ <,argBf=>
+ <,argMd=>
+ <,argAf=>
+ <,format=>
+ <,result=>
+ <,macarray=>
+ <,reuse=>
+)
+~~~~~~~~~~~~~~~~~~~~~~~
+
+**Arguments description**:
+
+1. `first` - *Required*, a space separated list of texts.
+
+2. `second` - *Required*, a space separated list of texts.
+
+* `function = cat` - *Optional*, default value is `cat`,
+ a function which will be applied
+ to corresponding pairs of elements of
+ the first and the second list.
+
+* `operator =` - *Optional*, default value is empty,
+ arithmetic infix operator used with elements
+ the first and the second list. The first
+ list is used on the left side of the operator
+ the second list is used on the right side
+ of the operator.
+
+* `argBf =` - *Optional*, default value is empty,
+ arguments of the function inserted
+ *before* elements the first list.
+ If multiple should be comma separated.
+
+* `argMd =` - *Optional*, default value is empty,
+ arguments of the function inserted
+ *between* elements the first list and
+ the second list.
+ If multiple should be comma separated.
+
+* `argAf =` - *Optional*, default value is empty,
+ arguments of the function inserted
+ *after* elements the second list.
+ If multiple should be comma separated.
+
+* `format=` - *Optional*, default value is empty,
+ indicates a format which should be used
+ to format the result, does not work when
+ the `operator=` is used.
+
+* `result=` - *Optional*, default value is empty,
+ indicates a name of newly created macroarray,
+ by default created macroarray name is concatenation
+ of first 13 characters of names of arrays used
+ to create the new one.
+
+* `macarray=N` - *Optional*, default value is `N`,
+ if set to `Y`/`YES` then a macro, named with
+ the array name, is compiled to create convenient
+ envelope for multiple ampersands, see the
+ `%array()` macro for details.
+
+* `reuse=Y` - *Optional*, default value is `Y`,
+ when one of the arrays is shorter then elements
+ are *reused* starting from the beginning.
+ If `CP` then function is executed on the *Cartesian
+ product* of arrays elements. Any other value will
+ cut the process with the end of the shorter array.
+ See examples for the details.
+
+### EXAMPLES AND USECASES: ####################################################
+
+See examples in `%zipArrays()` help for the details.
+
+---
+
+## >>> `%zipArrays()` macro: <<< #######################
+
+The zipArrays() and QzipArrays() macros
+allow to use a function on elements of pair of
+macro arrays.
+
+For two macroarrays the corresponding
+elements are taken and the macro applies a function, provided by user,
+to calculate result of the function on taken elements.
+
+When one of the arrays is shorter then elements are, by default,
+"reused" starting from the beginning. But this behaviour can be altered.
+See examples for the details.
+
+By default newly created macroarray name is concatenation
+of first 13 characters of names of arrays used to create the new one,
+e.g. if arrays names are `abc` and `def` then the result name is `abcdef`,
+if arrays names are `abcd1234567890` and `efgh1234567890` then the result
+name is `abcd123456789efgh123456789`
+
+The `zipArrays()` returns unquoted value [by `%unquote()`].
+The `QzipArrays()` returns quoted value [by `%superq()`].
+
+See examples below for the details.
+
+The `%zipArrays()` macro executes like a pure macro code.
+
+### SYNTAX: ###################################################################
+
+The basic syntax is the following, the `<...>` means optional parameters:
+~~~~~~~~~~~~~~~~~~~~~~~sas
+%zipArrays(
+ first
+ ,second
+ <,function=>
+ <,operator=>
+ <,argBf=>
+ <,argMd=>
+ <,argAf=>
+ <,format=>
+ <,result=>
+ <,macarray=>
+ <,reuse=>
+)
+~~~~~~~~~~~~~~~~~~~~~~~
+
+**Arguments description**:
+
+1. `first` - *Required*, a space separated list of texts.
+
+2. `second` - *Required*, a space separated list of texts.
+
+* `function = cat` - *Optional*, default value is `cat`,
+ a function which will be applied
+ to corresponding pairs of elements of
+ the first and the second list.
+
+* `operator =` - *Optional*, default value is empty,
+ arithmetic infix operator used with elements
+ the first and the second list. The first
+ list is used on the left side of the operator
+ the second list is used on the right side
+ of the operator.
+
+* `argBf =` - *Optional*, default value is empty,
+ arguments of the function inserted
+ *before* elements the first list.
+ If multiple should be comma separated.
+
+* `argMd =` - *Optional*, default value is empty,
+ arguments of the function inserted
+ *between* elements the first list and
+ the second list.
+ If multiple should be comma separated.
+
+* `argAf =` - *Optional*, default value is empty,
+ arguments of the function inserted
+ *after* elements the second list.
+ If multiple should be comma separated.
+
+* `format=` - *Optional*, default value is empty,
+ indicates a format which should be used
+ to format the result, does not work when
+ the `operator=` is used.
+
+* `result=` - *Optional*, default value is empty,
+ indicates a name of newly created macroarray,
+ by default created macroarray name is concatenation
+ of first 13 characters of names of arrays used
+ to create the new one.
+
+* `macarray=N` - *Optional*, default value is `N`,
+ if set to `Y`/`YES` then a macro, named with
+ the array name, is compiled to create convenient
+ envelope for multiple ampersands, see the
+ `%array()` macro for details.
+
+* `reuse=Y` - *Optional*, default value is `Y`,
+ when one of the arrays is shorter then elements
+ are *reused* starting from the beginning.
+ If `CP` then function is executed on the *Cartesian
+ product* of arrays elements. Any other value will
+ cut the process with the end of the shorter array.
+ See examples for the details.
+
+### EXAMPLES AND USECASES: ####################################################
+
+**EXAMPLE 1.** Simple concatenation of elements:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
+%array(a[*] x1-x3 (1:3))
+%array(b[*] x1-x5 (11:15))
+
+%put _user_;
+
+%zipArrays(a, b);
+%put _user_;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+**EXAMPLE 2.** Shorter list is "reused":
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
+%array(a[6] (1:6))
+%array(b[3] (10 20 30))
+
+%zipArrays(a, b, result=A_and_B, macarray=Y);
+%put %do_over(A_and_B);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+**EXAMPLE 3.** Use of the `operator=`:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
+%array(c[0:4] (000 100 200 300 400))
+%array(d[2:16] (1002:1016))
+
+%zipArrays(c, d, operator=+, result=C_plus_D, macarray=Y);
+%put (%do_over(C_plus_D));
+
+%put %C_plus_D(1);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+**EXAMPLE 4.** If one of array names is empty or an array does not exist:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
+%array(a[6] (1:6))
+%array(b[3] (10 20 30))
+
+%zipArrays(a, );
+%zipArrays(, b);
+
+%zipArrays(a, z);
+%zipArrays(z, b);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+**EXAMPLE 5.** Use of the `function=`:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
+%array(one[3] A B C, vnames=Y)
+%array(two[5] p q r s t, vnames=Y)
+
+%zipArrays(
+ one
+,two
+,function = catx
+,argBf = %str( )
+,format = $quote.
+,macarray=Y
+)
+%put %do_over(onetwo);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+**EXAMPLE 6.** To reuse or not to reuse, or maybe Cartesian product:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
+%array(e[3] (10 20 30))
+%array(f[2] (5:6))
+
+%zipArrays(e, f, reuse=n, operator=+, macarray=Y, result=_noReuse);
+%zipArrays(e, f, reuse=y, operator=+, macarray=Y, result=_yesReuse);
+%zipArrays(e, f, reuse=cp, operator=+, macarray=Y, result=_cartProdReuse);
+
+%put %do_over(_noReuse);
+%put %do_over(_yesReuse);
+%put %do_over(_cartProdReuse);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+**EXAMPLE 7.** Use middle argument:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
+%array(yr[3] (2018:2020))
+%array(mth[12] (1:12))
+
+%zipArrays(mth, yr, argMd=5, function=MDY, format=date11., macarray=Y);
+%put %do_over(mthyr);
+
+%zipArrays(mth, yr, argMd=5, function=MDY, format=date11., macarray=Y, reuse=cp);
+%put %do_over(mthyr);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+---
+
## License ####################################################################
Copyright (c) Bartosz Jablonski, since January 2019
diff --git a/packages/macroarray.zip b/packages/macroarray.zip
index fa3364c..b87a11a 100644
Binary files a/packages/macroarray.zip and b/packages/macroarray.zip differ