5

In SAS if I have a string or an Array like the following,

array x[4] $1 ('A' 'B' 'C' 'D');

I need to generate all "Unique" permutations of the elements like the following,

[ABCD]
[ABC]
[BCD]
[ACD]
[ABD]
[AB]
[AC]
[AD]
[BC]
[BD]
[CD]
[A]
[B]
[C]
[D]

Is there a function in SAS for generating all possible combinations of the array?

Joe
  • 62,789
  • 6
  • 49
  • 67
babsdoc
  • 693
  • 2
  • 11
  • 24
  • 3
    I think this is combination instead of permutation. – Lovnlust Mar 30 '15 at 07:18
  • `AB` and `BA` are different permutations but the same combination. – MatBailie Mar 30 '15 at 09:08
  • As asked this was asking for code. Asking the way I edited is more acceptable. – Joe Mar 30 '15 at 14:15
  • Thanks for the responses everyone. The only thing I was looking for is generating all possible "Unique" variations, so it does not matter what you call it combination or permutation both are ok for me. – babsdoc Mar 30 '15 at 17:30

4 Answers4

3

Assumption: I believe you are looking for combinations and not permutations, so the order does not matter, BA and AB are same thing.

Use call allcomb subroutine and comb function to find out the possible combinations.

Read more about allcomb and comb here

and here

In short -

  • call allcomb subroutine gives the possible combinations out of n elements when r of them are taken and
  • comb function gives you how many combinations it would be when out of n elements r of them are taken at a time.

data test(keep=my_string);
length my_string $50.;
  array a[4] $ ('A' 'B' 'C' 'D');

  n = dim(a);

   do k=1 to n;
         do j=1 to comb(n,k);
             call allcomb(j,k,of a[*]);
                 do i = 1 to k;
                    if i=1 then do; my_string="";counter=0;end;
                    counter=counter+1;
                    my_string=cat(compress(my_string),compress(a[i]));
                 if counter=k then output;

                 end;
           end;
    end;
run;
in_user
  • 1,948
  • 1
  • 15
  • 22
  • Thanks @NEOmen . I will surely look into this. Seems like this should be able to generate what I want. – babsdoc Mar 30 '15 at 17:31
3

A slightly different take on this is to use proc summary.

Create a dummy dataset. Assign each element of the array to a variable so we can feed it into proc summary:

data tmp;
  array arr[*] a b c d (1 1 1 1);
run;

Run proc summary.

proc summary data=tmp noprint missing;
  class a b c d;
  output out=combinations;
run;

You can also use the ways or types statements in proc summary to limit any combinations you may want.

Now the interesting side effect of doing this is that you get the _type_ column in the output dataset as well. In the example above the following values would be assigned:

D = 1
C = 2
B = 4
A = 8

So if the _type_ value in the output dataset is 13, then we know that the row was generated by combining A, B and D (8 + 4 + 1).

Robert Penridge
  • 8,424
  • 2
  • 34
  • 55
  • 2
    +1 Very nice. I'm so used to using `nway` that I often forget about the class grouping. I don't think you need the `var`, `sum`, `dummy` or any of the options though, the default behaviour with just `class` and `output out` should give the desired output. – SRSwift Mar 30 '15 at 17:10
  • Thanks Robert. I have never used a pro summary before. I will definitely try this. – babsdoc Mar 30 '15 at 17:32
  • 1
    @SRSwift Good points - I've updated the code based on your suggestions, thanks. – Robert Penridge Mar 30 '15 at 17:39
2

Here is a quick script that will find the combinations of the individual characters within a string. This could be easily adapted to work with arrays if you prefer. Rather than using the combinational functions and call routines (all*, lex*, ran*) this approach creates the permutations by using the binary representation of integers up to 2**len. I prefer this approach as I think it demonstrates what is happening, is more transparent and doesn't change the order of the array assignments.

data have;
    str = "123456"; output;
    str = "ABCD"; output;
run;
data want;
    set have;
    length comb $20.;
    len = length(str);
    /* Loop through all possible permutations */
    do _i = 0 to 2**len - 1;
        /* Store the current iteration number in binary */
        _bin = putn(_i, "binary" || put(len, best.) || ".");
        /* Initialise an empty output variable */
        comb = "";
        /* Loop through each value in the input string */
        do _k = 1 to len;
            /* Check if the kth digit of the binary representation is 1 */
            /* And if so add the kth input character to the output */
            if substr(_bin, _k, 1) = "1" then 
                comb = cats(comb,  substr(str, _k, 1));
        end;
        output;
    end;
    /* Clean up temporary variables, commented so you can see what's happening */
/*  drop _:; */
run;

If you do want permutations then a similar approach is possible using factoradic representations of the numbers. But, I would recommend that you use a combinational function instead as the conversions would be much more involved. It's probably quite a nice coding exercise for learning though.


It would be great if SAS had a function for reducing strings by boolean patterns, but it probably wouldn't get much use.

bsubstr("ABCD", "1010") --> "AC"
bsubstr("ABCD", "1110") --> "ABC"
bsubstr("ABCD", "0001") --> "D"
SRSwift
  • 1,700
  • 9
  • 11
  • Thanks @SRSwift. This is the most different way of doing it. No one has even suggested this to me, but it makes sense and looks interesting, I will try it out too. – babsdoc Mar 30 '15 at 17:35
0

SAS has in-built functions to calculate combinations & permutations, allcomb and allperm.

SAS Documentation for ALLCOMB function : http://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a003112305.htm

Chris J
  • 7,549
  • 2
  • 25
  • 25
  • Thank Chris, I had a look at the allcomb function but was not able to generate unique variations of the array elements. – babsdoc Mar 30 '15 at 17:33