Reputation: 137
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
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
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
Upvotes: 1
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;
Upvotes: 4