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

13 vues (au cours des 30 derniers jours)
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 commentaires
Stephen23
Stephen23 le 30 Jan 2019
Modifié(e) : Stephen23 le 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 le 30 Jan 2019
Modifié(e) : Marvin Heidkamp le 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 :)

Connectez-vous pour commenter.

Réponse acceptée

Jan
Jan le 30 Jan 2019
Modifié(e) : Jan le 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 commentaires
Jan
Jan le 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.

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Language Support dans Help Center et File Exchange

Produits


Version

R2017b

Community Treasure Hunt

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

Start Hunting!

Translated by