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;
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;
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
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
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;
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;
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
%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)
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?
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
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.