What is the fastest and most elegant way to calculate permutations of a vector of numbers?

7 views (last 30 days)
First question Is this this the best way to calculate the permutation of a number (I don't want an array of digits)?
>> n = 123;
>> x = str2double(cellstr(perms(int2str(n))))
x =
321
312
231
213
132
123
I rather doubt it...
Second question If it is, what is the best way to calculate the permutation matrix of a number vector (assuming the number of digits is prescribed)?
For example (in this case the numbers from 111 to 999):
Permut = nan(6,889);
for number = 111:999
counter = number-111+1;
Permut(:,counter) = str2double(cellstr(perms(int2str(number))));
end
Or more generic:
numDigits = 3;
nStart = str2double(strrep(num2str(ones( 1,numDigits)), ' ', ''));
nFinal = str2double(strrep(num2str(repmat(9,1,numDigits)), ' ', ''));
Permut = nan(factorial(numDigits),nFinal-nStart+1);
for number = nStart:nFinal
counter = number-nStart+1;
Permut(:,counter) = str2double(cellstr(perms(int2str(number))));
end
  4 Comments
Stephen23
Stephen23 on 30 Jan 2019
Edited: Stephen23 on 30 Jan 2019
Note that perms is documented to return the "...all permutations of the elements of vector v...". It does not return the unique permutations of the set of values, only of the elements of the vector. Do not confuse the unique permutations of vector elements with unique permutations of their values (which perms cares absolutely nothing about).
Your example shows that MATLAB correctly returns the six permutations of the elements of the vector [1,1,1], exactly as documented. But there is only one permutation of the set of values (1,1,1):
>> factorial(3) / factorial(3)
ans = 1
Marvin Heidkamp
Marvin Heidkamp on 30 Jan 2019
Edited: Marvin Heidkamp on 30 Jan 2019
Yes, thanks Stephen for that note. In my case the permutations of vector elements with unique permutations fit for my problem.
I like the brilliant explanation, thanks for the link :)

Sign in to comment.

Accepted Answer

Jan
Jan on 30 Jan 2019
Edited: Jan on 30 Jan 2019
Question 1:
perms(1:3) * [100; 10; 1]
Or the general case:
v = [2,5,4,8];
r = perms(v) * 10.^(numel(v)-1:-1:0).'
The multiple conversions by str2double, cellstr, and int2str are too indirect. If you want to work with numbers, stay at working with numbers.
If speed matters, replace perms by FEX: VChooseKO, which is about 10 times faster.
In your loop move the calculation of the power of 10 outside the loop.
  3 Comments
Jan
Jan on 30 Jan 2019
sprintf('%d', number) - 48 is most likely faster than int2str. I'd prefer to avoid the conversion to a char vector and back to numbers:
num = mod(floor(N ./ pow10, 10);
A small test:
numDig = 5;
pow10 = 10.^(numDig-1:-1:0).';
tic;
for k = 11111:99999
n = int2str(k) - 48;
end
toc
tic;
for k = 11111:99999
n = sprintf('%i', k) - 48;
end
toc
tic;
for k = 11111:99999
n = mod(floor(k ./ pow10), 10);
end
toc
% INT2STR: 1.66 sec
% SPRINTF: 0.96 sec
% MOD: 0.33 sec
int2str calls sprintf internally, so calling it directly saves the overhead. But sprintf is extremely powerful, and this costs time. It is cheaper to avoid a conversion, most of all because the expensive pow10 vector has been calculated already.

Sign in to comment.

More Answers (0)

Categories

Find more on Language Support in Help Center and File Exchange

Products


Release

R2017b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!