/*** HELP START ***//*
 
## >>> `%QzipEvalf()` macro: <<< <a name="qzipevalf-macro"></a> #######################  

The zipEvalf() and QzipEvalf() macro functions
allow to use a function on elements of pair of 
space-separated lists. 

For two space-separated lists of text strings 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 lists is shorter then elements are "reused" starting 
from the beginning.

The zipEvalf() returns unquoted value [by %unquote()].
The QzipEvalf() returns quoted value [by %superq()].

See examples below for the details.

The `%QzipEvalf()` macro executes like a pure macro code.

### SYNTAX: ###################################################################

The basic syntax is the following, the `<...>` means optional parameters:
~~~~~~~~~~~~~~~~~~~~~~~sas
%QzipEvalf(
    first
   ,second
  <,function=>
  <,operator=> 
  <,argBf=>
  <,argMd=>
  <,argAf=>
  <,format=>
)
~~~~~~~~~~~~~~~~~~~~~~~

**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.

*//*** HELP END ***/

%macro QzipEvalf(
   first
  ,second
  ,function = cat
  ,operator = 
  ,argBf=
  ,argMd=
  ,argAf=
  ,format=
)
/
des='The %zipEvalf() and %QzipEvalf() macro functions allows to use a function on elements of pair of lists.'
;
%local
  sepB sepM sepA 
  _F_ _S_ 
  NF NS  
  _Fk_ _Sk_
  _MAX_ _I_ _J_
  _RESULT_
;
%let _RESULT_ = ;

%if (%superq(first) = ) OR (%superq(second) = ) %then
  %do;
    %put NOTE: At least one of inputs is empty!;
    %put NOTE- Unchanged argument will be returned.;
    %let _RESULT_ = %superq(first)%superq(second);
    %superq(_RESULT_)
    %RETURN;
  %end;

%if \%superq(argBf)\ NE \\ %then %let sepB = ,;
%if \%superq(argMd)\ NE \\ %then %let sepM = ,;
%if \%superq(argAf)\ NE \\ %then %let sepA = ,;

%let NF = %qsysfunc(countw(%superq(first ), %str( ), SQ));
%let NS = %qsysfunc(countw(%superq(second), %str( ), SQ));

%let _MAX_ = %sysfunc(max(&NF., &NS.));
/*
%LET _Fk_ = 0;
%LET _Sk_ = 0;
*/

%DO  _I_ = 1 %TO &_MAX_.;
  %if &NF. > &NS. %then
    %do;
      %if &_Sk_. = &NS. %then %let _Sk_ = 1;
                        %else %let _Sk_ = %eval(&_Sk_. + 1);
      %let _Fk_ = &_I_.; 
    %end;
  %else
    %do;
      %if &_Fk_. = &NF. %then %let _Fk_ = 1;
                        %else %let _Fk_ = %eval(&_Fk_. + 1);
      %let _Sk_ = &_I_.; 
    %end;
  
  %let _F_ = %qscan(%superq(first),  &_Fk_., %str( ), SQ);
  %let _S_ = %qscan(%superq(second), &_Sk_., %str( ), SQ);
  /*%put >>%superq(_F_)<< >>%superq(_S_)<<;*/

  %if %superq(operator)= %then
    %do;
      %let _RESULT_ = 
        %qsysfunc(strip(%superq(_RESULT_) %qsysfunc(&function.(&argBf.&sepB.
                                                                %superq(_F_)
                                                               &sepM.&argMd.
                                                               ,%superq(_S_)
                                                               &sepA.&argAf.), 
                                          &format.) 
                        ));
      /*%put >>%superq(_RESULT_)<<;*/
    %end;
  %else
    %do;
      %let _RESULT_ = 
        %qsysfunc(strip(%superq(_RESULT_) %sysevalf(%superq(_F_) &operator. %superq(_S_)) 
                        ));
    %end;

%END;

%superq(_RESULT_)
/*%unquote(&_RESULT_.)*/
%RETURN;
%mend QzipEvalf;

/*** HELP START ***//*
 
### EXAMPLES AND USECASES: ####################################################

See examples in `%zipEvalf()` help for the details.

---

*//*** HELP END ***/

/**###################################################################**/
/*                                                                     */
/*  Copyright Bartosz Jablonski, since 2020.                           */
/*                                                                     */
/*  Code is under the MIT license. If you want - you can use it.       */
/*  But it comes with absolutely no warranty whatsoever.               */
/*  If you cause any damage or something - it will be your own fault.  */
/*  You've been warned! You are using it on your own risk.             */
/*  However, if you decide to use it don't forget to mention author.   */
/*  Bartosz Jablonski (yabwon@gmail.com)                               */
/*                                                                     */
/**###################################################################**/

