How to loop through an unknown number of matrix dimensions?

62 views (last 30 days)
KAE
KAE on 6 Mar 2018
Edited: KAE on 8 Aug 2019
I would like to loop through all dimensions of a n-dimensional matrix, but the matrix dimensions are unknown beforehand. Below is an example of generating a matrix of unknown dimensions, if it was a 2D matrix looping over those 2 dimensions. But in fact it could have 1-5 dimensions. Can you think of a good solution?
inputMatrixOfUnknownSize = ones(factor(round(rand(1)*500))); % Example matrix that could have 1 to many dimensions
dimList = size(inputMatrixOfUnknownSize) % List the dimensions
% If it was 2D, here's how we'd loop over those two dimensions...but it isn't necessarily 2D!
for iDim1 = 1:dimList(1)
for iDim2 = 1:dimList(2)
% Operate on each element. In reality the operation will not be the same for all dimensions.
outputMatrixOfUnknownSize(iDim1,iDim2) = outputMatrixOfUnknownSize(iDim1,iDim2)^2;
end
end
In my real code, the operation that is performed on each matrix element will depend on the dimension size, so I can't eliminate the loop in the example above.

Accepted Answer

Jan
Jan on 6 Mar 2018
Edited: Jan on 28 Feb 2019
You can use linear indexing, if you want to operate on all elements:
X = rand(2,3,4);
Y = zeros(size(X));
for k = 1:numel(X)
Y(k) = X(k) ^ 2;
end
Of course Y = X .^ 2 would be easier without a loop, but this is thought as demonstration only.
If you want to operate on submatrices, you can move them to the first dimensions temporarily:
X = rand(2,3,4,5,6);
operateOn = [3,5]; % Operate on submatrix along 3rd and 5th dimension
v = 1:ndims(X);
XX = permute(X, [operateOn, setdiff(v, operateOn)]);
sXX = size(XX);
XX = reshape(XX, [sXX(1:2), prod(sXX(3:end)]);
for k = 1:size(XX, 3)
submatrix = XX(:, :, k);
... do what you want
end
Another example is using a cell vector for indexing. If you want a subarray with indexing the the last two dimensions - independent from knowing how many dimensions the input has:
X = rand(2,3,4,5,6);
n = ndims(X);
index = cell(1, n);
index(:) = {':'};
index{end-1} = 3;
index{end} = 4;
Y = X(index{:}); % Equivalent to: X(:, :, :, 3, 4)
You can replace a bunch of nested loops by a single loop also using an index vector instead of scalar indices, see Answers: 333926-recursive-function-for-replacing-multiple-for-loops :
X = rand(2,3,4,5,6);
nv = ndims(X);
v = ones(1, nv);
vLim = size(X);
ready = false;
while ~ready
% Do what you need with X and the index vector v
...
% Update the index vector:
ready = true; % Assume that the WHILE loop is ready
for k = 1:nv
v(k) = v(k) + 1;
if v(k) <= vLim(k)
ready = false; % No, WHILE loop is not ready now
break; % v(k) increased successfully, leave "for k" loop
end
v(k) = 1; % Reset v(k), proceed to next k
end
end
This is equivalent to the following without the need to know the number of dimensions before:
for i1 = 1:size(X, 1)
for i2 = 1:size(X, 2)
for i3 = 1:size(X, 3)
for i4 = 1:size(X, 4)
for i5 = 1:size(X, 5)
v = [i1, i2, i3, i4, i5];
% Do what you need with X and the index vector v
...
end
end
end
end
end

More Answers (0)

Community Treasure Hunt

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

Start Hunting!

Translated by