Reputation: 49
Is there an easy way to get the first x permutations of a set?
For example a set with 5 characters {a,b,c,d,e} will have
5*5*5*5*5= 3125 permutations output
(repetition is allowed e.g. {a,a,a,a,a})
But I would like to have only the first 100 values for example
Upvotes: 2
Views: 464
Reputation: 18488
One way to generate all 'permutations' one at the time in lexicographical order, without having to store them all in memory:
function permute_chars(alphabet, nword, nmax)
if nargin < 3 % default to displaying all, this can be a huge number!
nmax = nchar^nword;
end
nchar = length(alphabet);
ind = zeros(1, nword);
i = 0;
while i < nmax
% just printing the permutaions, edit according to your needs
disp(cell2mat(alphabet(ind + 1)));
% calculate next indices, classic elementary school addition with carry
ind(end) = ind(end) + 1;
for j = nword:-1:2
if ind(j) == nchar
ind(j) = 0; % wrap around
ind(j-1) = ind(j-1) + 1; % carry
end
end
i = i + 1;
end
For sure I am forgetting some obscure function which would allow to implement this in fewer lines, but written like this it is clear how it works. Quick test:
>> alphabet = {'a', 'b', 'c', 'd', 'e'};
>> permute_chars(alphabet, 1)
a
b
c
d
e
>> permute_chars(alphabet, 2)
aa
ab
ac
ad
ae
ba
[... snip ...]
ed
ee
Printing only a limited amount of permutations:
>> permute_chars(alphabet, 5, 8)
aaaaa
aaaab
aaaac
aaaad
aaaae
aaaba
aaabb
aaabc
Upvotes: 2
Reputation: 16811
For a bit more flexibility in which range of permutations you get, you can use a function that, given a permutation, produces the next permutation in the series. In this implementation I've chosen to have the permutations wrap back around to the first, even if the input permutation is out of range.
function newperm = nextPerm(oldperm, base)
if any(oldperm >= base)
newperm = zeros(1,numel(oldperm));
return
end
idx = numel(oldperm);
newperm = oldperm;
while idx > 0
newperm(idx) = newperm(idx) + 1;
if newperm(idx) < base
return;
end
newperm(idx) = 0;
idx = idx - 1;
end
end
Permutation elements are 0-based (so max element is base-1).
p = [4 4 4 4 4]
nextPerm(p, 5)
ans =
0 0 0 0 0
p = [0 0 0 0 0]
nextPerm(p, 5)
ans =
0 0 0 0 1
p = [3 4 1 0 2]
nextPerm(p, 5)
ans =
3 4 1 0 3
p = [3 4 5 0 2] %// invalid value '5'
nextPerm(p, 5)
ans =
0 0 0 0 0
To get a range, just feed it through a loop:
myPerms = zeros(5);
myPerms(1,:) = [3 1 2 0 4];
for k = 2:5
myPerms(k,:) = nextPerm(myPerms(k-1,:), size(myPerms,1));
end
myPerms =
3 1 2 0 4
3 1 2 1 0
3 1 2 1 1
3 1 2 1 2
3 1 2 1 3
To map the permutation to your alphabet, just add 1 to the vector and use it as an index:
alphabet = ['a', 'b', 'c', 'd', 'e'];
word = alphabet(myPerms(1,:)+1)
word = dbcae
Upvotes: 1
Reputation: 7817
To select 100 random unique samples from numbers 1:n
, with repetitions allowed (sampling with replacement), you can use randi
or similar to create a list of a bit more than 100 x n
random samples, unique
them to remove duplicates, and then take the first 100.
For example, using randi
:
% from numbers 1:n, create 200 by n random matrix
sample_list = randi(n,[200, n]);
% remove duplicates
sample_list = unique(sample_list,'rows');
% you should probably error check here
% presuming there's >100 options left, take 100 of them
sample_list = sample_list(1:100,:);
sample_list
will be a numeric matrix, but you can easily use it as an index into other things if needed:
my_set = {'a','b','c','d','e'}; % 1 x 5 cell
my_permutes = my_set(sample_list); % 100 x 5 cell
This avoids having to calculate every single possible option, which for larger n
would become problematic.
Upvotes: 1
Reputation: 513
You can use P = perms(S)
to get all the permutations of set S
, and then if you wanted 100 you could do P(1:100,:)
.
For random you could use P(randperm(size(P,1),100),:)
.
If you know need to be more specific about the permutations, then you can use permute
with an order
parameter - http://uk.mathworks.com/help/matlab/ref/permute.html
Upvotes: 2