Creating a Variable Number of Nested 'for' Loops
8 次查看(过去 30 天)
显示 更早的评论
Hi all,
I am trying to iterate down every column of array x, and extract all combinations when the sum of these elements is equal to one.
At the moment this is being made possible by having a for loop iterate down each individual column, and then using an if statement to pause the loop and store these combinations in the array 'Combinations'.
N = 3;
x = zeros(6, N);
x(1, :) = 0;
x(2, :) = 0.2;
x(3, :) = 0.4;
x(4, :) = 0.6;
x(5, :) = 0.8;
x(6, :) = 1;
a = 0;
A = 1;
for i = 1:size(x, 1)
for j = 1:size(x, 1)
for k = 1:size(x, 1)
X = x(i, 1) + x(j, 1) + x(k, 1);
if X == 1
Combinations(A, 1) = x(i, 1);
Combinations(A, 2) = x(j, 2);
Combinations(A, 3) = x(k, 3);
a = a + 1;
A = A + 1;
continue
end
end
end
end
However, if the number of columns in x were to change, I would need to be able to vary the number of for loops depending on the value of N. Is this possible/is there an alternative method of achieving a similar result?
Any help would be appreciated. Thanks!
3 个评论
Jan
2018-2-8
Typo: I guess, that you do not have 3 times "for i", but it should be "for i, for j, for k".
采纳的回答
Walter Roberson
2018-2-8
Use https://www.mathworks.com/matlabcentral/fileexchange/10064-allcomb-varargin- allcomb() from the File Exchange, and then throw away the entries that do not match your constraint.
0 个评论
更多回答(1 个)
Jan
2018-2-8
编辑:Jan
2018-2-8
Attention: Consider rounding effects:
0.1 + 0.1 + 0.1 == 0.3 % FALSE!!!
So do not check if the sum equals 1.0 exactly, but if the distance is smaller than a specific limit, e.g. 3*eps.
You can use an index vector of variable size instead of a set of loops. See e.g. https://www.mathworks.com/matlabcentral/answers/333926-recursive-function-for-replacing-multiple-for-loops#answer_262156 .
N = 3;
% x = zeros(6, 1); % Not [6, N] Or easier:
x = [0, 0.2, 0.4, 0.6, 0.8, 1.0];
nx = numel(x);
Lim = 30 * eps; % Consider rounding errors!!!
v = [1, 1, 1]; % ONE index vector
ready = false;
Combinations = zeros(1e6, N); % Bold pre-allocation
iC = 1;
while ~ready
% Test value and store result:
if abs(sum(x(v)) - 1.0) < Lim % Not: sum(x(v)) == 1.0 !!!
Combinations(iC, :) = v;
iC = iC + 1;
end
% Shift the index vector:
ready = true; % Claim temporarily that the WHILE loop is ready
for k = 1:N
v(k) = v(k) + 1;
if v(k) <= nx
ready = false;
break; % v(k) increased successfully, leave "for k" loop
end
v(k) = 1; % v(k) reached nx: reset it, proceed with next v
end
end
Combinations = Combinations(1:iC); % Crop the pre-allocated array
This is equivalent to N for loops running from 1 to nx. It is easy to adjust it to specific limits for each loop.
It is much cheaper to pre-allocate a too large array, than letting an array grow iteratively.
For the efficient creation of permutations with repetitions and order see the fast C-Mex function FEX: VChooseKRO (must be compiled before using).
0 个评论
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Loops and Conditional Statements 的更多信息
产品
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!