MATLAB Answers

dynamic subindices <-> linear indices conversion, data crop /trim

4 views (last 30 days)
Is there a way to dynamically crop N-dimensional data into an N-1 set? I have no knowledge of N before runtime, nor of the dimension on which to crop.
I need to write a 'trimming' function of the form:
>> data_NDm1 = one_dim_trim(ndata, 1, x);
% which will allow me to replace any of the
>> data_NDm1 = data_ND(x,:);
>> data_NDm1 = data_ND(x,:,...,:);
% or replace
>> data_NDm1 = ndata(:,x,:,...,:);% with
>> data_NDm1 = one_dim_trim(ndata, 2, x);
I have already written a 'cropping' function like
>> data_1D = one_dim_crop(ndata, [3, NaN, 4, 7]);
% which takes variable size arguments and replaces:
>> data_1D = ndata(3, :, 4, 7);
...but I'm kind of stuck here :-)
Any hints would be greatly appreciated.

  1 Comment

tudor dima
tudor dima on 27 Apr 2018
corrected format below ---------------------
Is there a way to dynamically trim an N-dimensional matrix into an N-1 matrix given a dimension and the wanted subindex?
I have no knowledge of N before runtime, nor of the dimension on which to trim.
Details:
I need to write a 'trimming' function of the form:
>> data_NDm1 = one_dim_trim(data_ND, 1, a);
% which will allow me to replace any of the
>> data_NDm1 = data_ND(a,:);
>> data_NDm1 = data_ND(a,:,...,:);
% or replace
>> data_NDm1 = data_ND(:,b,:,...,:);% with
>> data_NDm1 = one_dim_trim(data_ND, 2, b);
I have already written a 'cropping' function of the form:
>> data_1D = one_dim_crop(data_ND, [a, NaN, c, ..., z]);
% which takes variable size arguments and replaces:
>> data_1D = data_ND(a, :, c, ..., z);
...but I'm kind of stuck here :-)
Any hints would be greatly appreciated.

Sign in to comment.

Accepted Answer

Stephen Cobeldick
Stephen Cobeldick on 27 Apr 2018
Edited: Stephen Cobeldick on 27 Apr 2018
Method one: comma-separated list: many MATLAB users don't realize that indices can be provided as a comma-separated list, and that the colon can then be the char ':'. This makes the task simply:
>> A = rand(3,4,5,6);
>> C = repmat({':'},1,ndims(A));
>> C{3} = [1,3]; % C{d} = x
>> Z = A(C{:});
>> size(Z)
ans =
3 4 2 6
Method two: alternatively call subsref directly: subsref allows overloading of indexing... e.g. useful for flexibility in defining the indices:
>> A = rand(3,4,5,6);
>> C = repmat({':'},1,ndims(A));
>> C{3} = [1,3];
>> Z = subsref(A,substruct('()',C));
>> size(Z)
ans =
3 4 2 6
Bonus these can easily be put these into a function, as requested:
function B = myidx(A,d,x)
n = max(ndims(A),d);
C = repmat({':'},1,n);
C{d} = x;
B = A(C{:});
end
And then to use it:
>> A = rand(3,4,5,6);
>> B = myidx(A,3,[1,3]);
>> size(B)
ans =
3 4 2 6
All of these work dynamically, as one can specify the dimension d and required index x.
Use permute to remove singleton dimensions, if required.

  1 Comment

tudor dima
tudor dima on 27 Apr 2018
Brilliant, it works like a charm, thanks !
I didn't know about subsref, as it doesn't show up under "see also" .
Meanwhile I had written something that works, will check for speed just in case, although I don't really expect it to be faster than subsref.
Thanks again.

Sign in to comment.

More Answers (0)