Creating a Variable Number of Nested 'for' Loops

8 views (last 30 days)
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 Comments
Jan
Jan on 8 Feb 2018
Typo: I guess, that you do not have 3 times "for i", but it should be "for i, for j, for k".

Sign in to comment.

Accepted Answer

Walter Roberson
Walter Roberson on 8 Feb 2018
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.

More Answers (1)

Jan
Jan on 8 Feb 2018
Edited: Jan on 8 Feb 2018
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).

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Tags

Products

Community Treasure Hunt

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

Start Hunting!