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

The `%QdedupListX()` macro deletes duplicated values from 
a *X-separated* list of values, where the `X` represents 
a *single character* separator. List, including separators, 
can be no longer than a value carried by a single macro variable.

**Caution.** The value of `X` *has to be* in **the first** byte of the list,
             just after the opening bracket, i.e. `(X...)`.

Returned value is **quoted** with `%superq()`. Leading and trailing spaces are ignored.

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

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

The basic syntax is the following, the `<...>` means optional parameters:
~~~~~~~~~~~~~~~~~~~~~~~sas
%QdedupListX(
XlistXofXxXseparatedXvalues
)
~~~~~~~~~~~~~~~~~~~~~~~

**Arguments description**:

1. `list` - A list of *X-separated* values. 

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

%macro QdedupListX()/parmbuff minoperator mindelimiter=' ';
  %local _wc_ _I_ _element_ _list_ _sep_;
  %if %superq(syspbuff) ne %str(%(%)) %then
    %do;
      %let _sep_= %qsubstr(&syspbuff., 2, 1);
      %let syspbuff = %qsubstr(&syspbuff., 3, %eval(%length(&syspbuff.)-3));
      %let _wc_ = %qsysfunc(countw(&syspbuff., %superq(_sep_)));
      %let _list_ = %unquote(%qscan(&syspbuff., 1, %superq(_sep_)));

      /*%put *&_sep_*&syspbuff*&_wc_*&_list_*;*/ /*<- for debuging*/

      %if %superq(_sep_) NE %str( ) %then 
        %do _I_ = 2 %to &_wc_.;
          %let _element_ = %unquote(%qscan(&syspbuff., &_I_, %superq(_sep_)));
          /*%put *&_element_*;*//*<- for debuging*/        
          %if %sysevalf(%superq(_element_) ne ) %then
            /* the 0+0 at the end is for dot(.) separator because findw returns dot */
            %if not (%sysevalf( %qsysfunc(findw(%superq(_list_),%superq(_element_),%superq(_sep_)))0+0)) %then
              %do;
                %let _list_ = %superq(_list_)%superq(_sep_)%superq(_element_);
              %end;
        %end;
      %else
        %do _I_ = 2 %to &_wc_.;
          %let _element_ = %qscan(&syspbuff., &_I_, &_sep_.);
          %if (%superq(_element_) ne ) %then
            %if not(%superq(_element_) in %superq(_list_)) %then
              %do;
                %let _list_ = %superq(_list_) %superq(_element_);
              %end;
        %end;
    %end;
%superq(_list_)
%mend QdedupListX;

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

**EXAMPLE 1.** Basic use-case one. 
    Delete duplicated values from a list.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
  %put *%QdedupListX(|a|b|c|b|c)*;

  %put *%QdedupListX( a b c b c)*;

  %put *%QdedupListX(,a,b,c,b,c)*;

  %put *%QdedupListX(XaXbXcXbXc)*;

  %put *%QdedupListX(/a/b/c/b/c)*;

  %put *%QdedupListX(%str(;a;b;c;b;c))*;

  %put *%QdedupListX(%nrstr(&a&b&c&b&c))*;

  %put *%QdedupListX(%nrstr(%a%b%c%b%c))*;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**EXAMPLE 2.** Leading and trailing spaces are ignored. 
    Delete duplicated values from a list.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
  %put *%QdedupListX(| a | b.b |  c | b.b| c    )*;

  %put *%QdedupListX(. a . b b .  c . b b. c    )*;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**EXAMPLE 3.** Macro variable as an argument. 
    Delete duplicated values from a list.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
  %let list = 4$5.5$6$1$2$3$1$2$3$4$5.5$6;
  %put *%QdedupListX($&list.)*;

  %let list = 4$ 5.5$ 6$ 1$ 2$ 3$ 1$ 2$ 3$ 4$ 5.5$ 6$;
  %put *%QdedupListX( &list.)*;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

---

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

/**###################################################################**/
/*                                                                     */
/*  Copyright Bartosz Jablonski, since October 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)                               */
/*                                                                     */
/**###################################################################**/
