How to loop through an unknown number of matrix dimensions?

30 views (last 30 days)
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)

Categories

Find more on Creating and Concatenating Matrices in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!