Alternative for nested for loop

I need to implement this logic to make combinations of a matrix. This code is a bit cumbersome since I need to add more rows and columns at some point. Is there a simpler way to do this?
k = 0;
for x1 = 1:2
for x2 = 1:2
for x3 = 1:2
for y1 = 1:2
for y2 = 1:2
for y3 = 1:2
for z1 = 1:2
for z2 = 1:2
for z3 = 1:2
k = k+1;
JV{k} = [J1(1,x1),J2(1,x2),J3(1,x3);
J1(2,y1),J2(2,y2),J3(2,y3);
J1(3,z1),J2(3,z2),J3(3,z3)];
end
end
end
end
end
end
end
end
end
J1, J2 & J3 are 3x2 matrices.

1 Comment

You can probably use a function that generates all permutations to simplify this. Maybe even ndgrid could help you out.

Sign in to comment.

 Accepted Answer

Adam Danz
Adam Danz on 20 Feb 2021
Edited: Adam Danz on 21 Feb 2021
> Is there a simpler way to do this?
As long as you're preallocating the JV cell array, your approach is very simple, fast, and readable. The alternative below does the same thing but is much less readable and it's slower (there may be faster ways than mine).
However, depending on how you're using the JV cell array, it may be more efficient to pack those values into a 3D array instead. So, my recommendations are
  1. keep the nested loops; it's fast, readable, and simple.
  2. definitely preallocate the JV variable whether you're using a cell array or 3D array.
  3. Consider using a 3D array for JV.
% Demo values; J1 J2 and J3 must be the same size
J1 = [1:3;4:6]';
J2 = J1.*10;
J3 = J2.*10;
allJ = cat(3,J1, J2, J3); % 3x2x3
colidx = flipud(combvec(1:2,1:2,1:2,1:2,1:2,1:2,1:2,1:2,1:2)); % * see note
rowidx = repmat([1 1 1 2 2 2 3 3 3]', 1, size(colidx,2));
pageIdx = repmat([1 2 3 1 2 3 1 2 3]', 1, size(colidx,2));
ind = sub2ind(size(allJ), rowidx, colidx, pageIdx);
JVec = allJ(ind);
JArray = permute(reshape(JVec, 3,3,[]),[2,1,3]); % you could stop here and use a 3D array
JV = arrayfun(@(page){JArray(:,:,page)}, 1:size(JArray,3));
I ran your nested conditional version with the same inputs and confirmed that both methods produce the same results.
Note: combvec requires the deeplearning toolbox. See this answer for an alternative.

6 Comments

Fawad Khan
Fawad Khan on 21 Feb 2021
Edited: Fawad Khan on 21 Feb 2021
Thank you @Adam Danz. This method gives the same results. Also, it's almost as fast as the method I was using.
I do preallocate the JV cell array as JV{2^(m*n)} = []. Since each JV is a 3x3 (mxn) matrix.
Interesting way to preallocate the cell array. The only problem with that is if JV already exists you're not really clearing it or resetting it to a cell array of empty values. The standard way to preallocate a cell array is,
JV = cell(1, 2^(m*n));
If you decide to go with a 3D array,
J = nan(3,3,2^(m*n));
You're right.
Although JV = cell(1,2^(m*n)) and JV{1,2^(m*n)} = [] do the same thing (see https://www.mathworks.com/help/matlab/matlab_prog/preallocate-memory-for-a-cell-array.html).
The way I did it, it may not clear the cell array if it already exists but the values will get overwritten in any case; like we preallocate arrays with zeros or ones and then we overwrite.
They don't do quite the same thing. This is relevant mainly if JV is too large, in which case your method would leave old values in the last elements.
I disagree with the documentation that those statements are equivalent (btw @Fawad han I edited your comment to fix the broken URL).
1. Problems when cell array size decreases
Here's an example of what Rik said.
for i = [ 5 4 3];
c{1,i} = [];
disp(numel(c))
end
5 5 5
Compare that to
for i = [ 5 4 3];
c = cell(1,i);
disp(numel(c))
end
5 4 3
2. Problems when var already exists but isn't a cell array
c = 1:20;
c{1,5} = []
Unable to perform assignment because brace indexing is not supported for variables of this type.
But this works,
c = cell(1,5)
1×5 cell array
{0×0 double} {0×0 double} {0×0 double} {0×0 double} {0×0 double}
I see. I've been using it wrong then. Thank you for correcting me.

Sign in to comment.

More Answers (0)

Products

Tags

Asked:

on 20 Feb 2021

Commented:

on 23 Feb 2021

Community Treasure Hunt

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

Start Hunting!