BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
dwarden3
Fluorite | Level 6

Hello,

 

I am trying to code all of the permutations of given length such that I get the following in one dataset: 

a

b

c

..............

a a 

a b

b a

.............

a a a 

a a b

a a c

a a d

a a e

...........

etc. 

 

Is there a way to do this iteratively in either base SAS or IML? I am able to make this using repetition in IML. 

 

 

 

Current code example (but repeated out to however many times):

proc IML;
c_num=repeat(1,5);
perm1=T(1:5);
p_num=T(1:5);
index=T(1:5);
create OutData1_org var {c_num, perm1, p_num, index}; /* create Work.OutData for writing */
append; /* write data in x and y */
close OutData1_org;

data OutData1;
set OutData1_org;
format perm $18.;
perm=cats(perm1);
drop perm1;
run;

proc IML;
a=T(1:5);
c_num=repeat(2,25);
perm1=repeat(a, {5 5 5 5 5});
perm2=repeat(1:5,5);
p_num=T(6:30);
index=T(1:25);
create OutData2_old var {c_num, perm1, perm2,p_num, index}; /* create Work.OutData for writing */
append; /* write data in x and y */
close OutData2_old;

data OutData2;
set OutData2_old;
perm_test=put(perm1,$1.)||" "||put(perm2,$1.);
perm=put(perm_test, $18.);
drop perm1 perm2 perm_test;
run;

 

data Perms;
set OutData1 OutData2;
run;

1 ACCEPTED SOLUTION

Accepted Solutions
Rick_SAS
SAS Super FREQ

I see. You don't want permutations nor do you want combinations. You are looking for the Cartesian product of a set with itself k times, where k=1,2, and 3.  In the SAS/IML language, you can form a Cartesian product by using the ExpandGrid function.

 

If you want to write this information to a rectangular data set, you need to decide how to combine the results that only have 1 column (k=1) with the results that have two or three columns (k=2 and k=3). In the following program, I used missing values for the columns that are not used.

 

proc iml;
set = T( 0:5 );
/* generate all possible triplets (x1,x2,x3) where the x_i are in {0,1,2,3,4,5} */
p1 = set;
p2 = expandgrid(set, set);
p3 = expandgrid(set, set, set);


/* write to data set */
create Values var {Length, x1, x2, x3};

N = nrow(p1); /* N = 6 */
Length=j(N,1,1);
x1 = p1;  x2=j(N,1,.); x3=j(N,1,.); 
append;

N = nrow(p2); /* N = 6**2 = 36  */
Length=j(N,1,2);
x1 = p2[,1];  x2=p2[,2]; x3=j(N,1,.); 
append;

N = nrow(p3); /* N = 6**3 = 216 */
Length=j(N,1,3);
x1 = p3[,1];  x2=p3[,2]; x3=p3[,3];
append;

close;
quit;

View solution in original post

8 REPLIES 8
Rick_SAS
SAS Super FREQ

Do you want permutations or combinations? Run the following program, which shows how to get all permutation (by using the ALLPERM function) or all combinations of k elements (by using the ALLCOMB function):

 

proc iml;
set = 1:3;
/* generate all permutations of 3 elements */
p = allperm(set);
print p;

/* if you want letters, index into the set {A, B, C} */
letters = {A B C};
p2 = letters[p];
p3 = shape(p2, 0, 3);
print p3;

/* generate all combination of 3 elements taken k at a time */
do k = 1 to 3;
   ck = allcomb(3, k);
   print "----" k "----", ck;
end;

For more information, see

 

dwarden3
Fluorite | Level 6

Hi Rick, 

 

Set p you made is correct except I also need: 000, 111, 444 etc. and things like 501,432, etc. I want all of the possible combinations that are x long from y items (0 to 5). 

 

So when the set is length 1, I would have: 0, 1, 2, 3, 4, 5.

With two: 0 0, 0 1, 0 2 ,0 3, 0 4, 0 5, 1 0 , 1 1, etc. 

 

Thank you

Rick_SAS
SAS Super FREQ

I see. You don't want permutations nor do you want combinations. You are looking for the Cartesian product of a set with itself k times, where k=1,2, and 3.  In the SAS/IML language, you can form a Cartesian product by using the ExpandGrid function.

 

If you want to write this information to a rectangular data set, you need to decide how to combine the results that only have 1 column (k=1) with the results that have two or three columns (k=2 and k=3). In the following program, I used missing values for the columns that are not used.

 

proc iml;
set = T( 0:5 );
/* generate all possible triplets (x1,x2,x3) where the x_i are in {0,1,2,3,4,5} */
p1 = set;
p2 = expandgrid(set, set);
p3 = expandgrid(set, set, set);


/* write to data set */
create Values var {Length, x1, x2, x3};

N = nrow(p1); /* N = 6 */
Length=j(N,1,1);
x1 = p1;  x2=j(N,1,.); x3=j(N,1,.); 
append;

N = nrow(p2); /* N = 6**2 = 36  */
Length=j(N,1,2);
x1 = p2[,1];  x2=p2[,2]; x3=j(N,1,.); 
append;

N = nrow(p3); /* N = 6**3 = 216 */
Length=j(N,1,3);
x1 = p3[,1];  x2=p3[,2]; x3=p3[,3];
append;

close;
quit;
dwarden3
Fluorite | Level 6
Thank you so much! I knew there was a way to do this with IML.
ErikLund_Jensen
Rhodochrosite | Level 12

Hi @dwarden3 

 

Here are two other ways, both in base SAS:

 

* Data Step
  Permutations as iterations over letter array and concatenation of elements;
data test1 (drop=letter: i j k);
  length permutation $3;
  array letter {3} $ ('A','B','C');
  do i = 1 to 3;
    do j = 1 to 3;
      do k = 1 to 3;
        permutation = catt(letter{i},letter{j},letter{k});
        output;
      end;
    end;
  end;
run;


* Proc SQL 
  Permutations as cartesian products of joining letter data set and concatenation of elements;
proc sql;
  create table t1 (letter char(1));

  insert into t1 
    set letter = 'A'
    set letter = 'B'
    set letter = 'C';

  create table t2 as
    select catt(a.letter,b.letter) as permutation
    from t1 as a, t1 as b;

  create table test2 as
    select catt(a.permutation,b.letter) as permutation
    from t2 as a, t1 as b;
quit;

 

 

yabwon
Onyx | Level 15

Some time ago I did this macro (tested up to 13), maybe you find it useful:

proc format;
  value perm
    1  = A
    2  = B
    3  = C
    4  = D
    5  = E
    6  = F
    7  = G
    8  = H
    9  = J
    10 = J
    11 = K
    12 = L
    13 = M
    other = "X"
  ;
run;
 
%macro perm(level,print=1);
  %do level = 1 %to &level.;
    %if 1 = &level. %then
      %do;
        data _1;
          _1_1 = 1;
        run;
      %end;
    %else
      %do;
        data _&level.;
          set _%eval(&level. - 1);
          array old[*] _%eval(&level. - 1)_:;
          array new[&level.] _%eval(&level.)_1 - _%eval(&level.)_&level.;
 
          do j = 1 to &level.;
            new[j] = &level.;
            do k = 1 to %eval(&level. - 1);
              new[k+(k>=j)] = old[k];               
            end;
            output;
          end;
        keep _%eval(&level.)_:;
        run;
 
        proc delete data = _%eval(&level. - 1);
        run;
      %end;
  %end;
 
  %if 1 = &print. %then
    %do;
      proc sort data = _%eval(&level. - 1);
        by _all_;
      run;
      proc print data = _%eval(&level. - 1);
        format _all_ perm.;
      run;
    %end;
%mend perm;
 
%perm(5);
 
%perm(8,print=0);

If you comment out:

        proc delete data = _%eval(&level. - 1);
        run;

you will get all intermediate datasets.

 

[EDIT:]

Format _perm_ is just for print out, but you can easily modify final dataset with it.

 

Bart

_______________
Polish SAS Users Group: www.polsug.com and communities.sas.com/polsug

"SAS Packages: the way to share" at SGF2020 Proceedings (the latest version), GitHub Repository, and YouTube Video.
Hands-on-Workshop: "Share your code with SAS Packages"
"My First SAS Package: A How-To" at SGF2021 Proceedings

SAS Ballot Ideas: one: SPF in SAS, two, and three
SAS Documentation



Ksharp
Super User
%macro perm(n=);
proc plan seed=12345 ;
%do i=1 %to &n.;
factors
 %do j=1 %to &i.;
   x&j.=&n. perm
 %end;
/noprint;
output out=x&i.;
run;
%end;
quit;

data want;
 set x1-x&n.;
run;
%mend;


%perm(n=5)
Tom
Super User Tom
Super User

What you show as output does not look at all like a dataset.  Datasets have a fixed number of variables.  You cannot have 3 rows with only one variable and then another three rows with 2 variables.

 

So what form do you want the output to take?

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 8 replies
  • 1224 views
  • 1 like
  • 6 in conversation