anna
anna

Reputation: 137

Create all possible combination in SAS without using functions

Is there a way to create all possible combinations of strings in SAS without using functions (ideally using loops). I say that because I want to adapt that code to run in SAS CASL which does not support many sas functions just yet. Here is my problem: {"a","b","c","d"} and would like to create all combinations: {{a,b,c,d},{b,c,d},{c,d},{d},{c},{b,d},{d},{b},{b,c},{c},{b},{a,c,d},.....etc.

Any help is appreciated. Thanks in advance

Upvotes: 1

Views: 673

Answers (3)

Bill Huang
Bill Huang

Reputation: 4648

If you don't want any SAS functions, brute-force generation in the data step is doable by increasing i = 1 to 2^N-1 and take all the digits corresponding to the elements. Here is a showcase:

Data

data values;
     input val $1;
     cards;
a
b
c
d
;run;

Code

Edit: make a macro to detect the length of data automatically.

%macro gen(indata, outdata);

    proc sql noprint;
        select count(*) into :N from &indata;
    quit;
    
    data &outdata(keep=B:);
        array A[&N] $1;
        array B[&N] $1;
        /* setup: A1="a"; A2="b"; A3="c"; A4="d"; */
        i = 1;
        do while (i <= &N);
            set &indata;
            A[i] = val;
            i = i + 1;
        end;
        
        i = 1;
        do while (i < 2**&N);
            i2 = i;
            j = 1;
            do while (j <= &N);
                if (mod(i2, 2) = 1) then B[j] = A[j];
                else B[j] = .;
                i2 = floor(i2 / 2);
                j = j + 1;
            end;
            output;
            i = i + 1;
        end;
    run;
%mend;

/* execute */    
%gen(values, out)

Output

| obs | B1 | B2 | B3 | B4 |
|-----|----|----|----|----|
| 1   | a  | .  | .  | .  |
| 2   | .  | b  | .  | .  |
| 3   | a  | b  | .  | .  |
| 4   | .  | .  | c  | .  |
| 5   | a  | .  | c  | .  |
| 6   | .  | b  | c  | .  |
| 7   | a  | b  | c  | .  |
| 8   | .  | .  | .  | d  |
| 9   | a  | .  | .  | d  |
| 10  | .  | b  | .  | d  |
| 11  | a  | b  | .  | d  |
| 12  | .  | .  | c  | d  |
| 13  | a  | .  | c  | d  |
| 14  | .  | b  | c  | d  |
| 15  | a  | b  | c  | d  |

Upvotes: 0

Richard
Richard

Reputation: 27508

Iterate through all bit combinations (i.e. 1 to 2item_count-1). Reduce computational overhead using precomputed bitmasks and a single CATX over an array of bit selected items.

data items;
input item $ @@;
datalines;
a b c d
;

data want;
  array items(0:31) $ _temporary_;
  array masks(0:31) _temporary_;
  array combos(0:31) $8 _temporary_;

  do _n_ = 0 by 1 until (lastitem);
    set items end=lastitem;
    items(_n_) = item;
    masks(_n_) = 2**_n_;
  end;

  do bits = 1 to 2**(_n_+1)-1;
    call missing(of combos(*));
    do bit = 0 to _n_;
      if band(bits,masks(bit)) then combos(bit) = items(bit);
    end;
    combo = catx(',', of combos(*));
    output;

    guard + 1;
    if guard > 1e6 then stop; * come on now! lets be reasonable;
  end;

  keep combo;
run;

Output

enter image description here

Upvotes: 1

data _null_
data _null_

Reputation: 9109

Is this something you can use.

data test;
   a='a';
   b='b';
   c='c';
   d='d';
   run;
proc summary data=test descendtypes chartype;
   class a b c d;
   output out=combo;
   run;
proc print;
   run;

enter image description here

Upvotes: 4

Related Questions