13

I have as entry a matrix which can have an several number of dimensions : n × m or n × m × p or n × m × p × q or ...

What I want to do is to access to the last dimension, something like:

data = input(:,:,1)

The problem is that the number of : can change.

Rody Oldenhuis
  • 37,726
  • 7
  • 50
  • 96
Romain
  • 340
  • 1
  • 8
  • 1
    Is the possible number of dimensions finite (and small)? If so, you could query the size of the matrix using the `size` function and have various cases using a `switch` statement. – am304 Nov 13 '13 at 14:07
  • 2
    Note that it is not recommended to use a variable called `input` as this is the name of a standard function. – Dennis Jaheruddin Nov 13 '13 at 14:12
  • possible duplicate of [Indexing of unknown dimensional matrix](http://stackoverflow.com/questions/10146082/indexing-of-unknown-dimensional-matrix) – Eitan T Nov 14 '13 at 12:16
  • @EitanT Though the solution to that question should be applicable here, this one is more specific. Hence 'shortcuts' may be taken here that are not viable solutions for the linked question. – Dennis Jaheruddin Dec 24 '13 at 16:26
  • @DennisJaheruddin then perhaps it's a duplicate of [Using a colon for indexing in matrices of unknown dimensions](http://stackoverflow.com/questions/16924273/using-a-colon-for-indexing-in-matrices-of-unknown-dimensions). I go by the theory that most of the new questions are recycled... :) – Eitan T Dec 24 '13 at 16:49
  • @EitanT I agree that with some minor rewording that question would make this one obsolete. Have suggested a merge as that question seems to be worded better, whilst this one has a larger variety of answers. – Dennis Jaheruddin Dec 27 '13 at 08:34

6 Answers6

14

You should make use of the fact that indices into an array can be strings containing ':':

>> data = rand(2, 2, 2, 5);
>> otherdims = repmat({':'},1,ndims(data)-1);
>> data(otherdims{:}, 1)
ans(:,:,1) =
    7.819319665880019e-001    2.940663337586285e-001
    1.006063223624215e-001    2.373730197055792e-001
ans(:,:,2) =
    5.308722570279284e-001    4.053154198805913e-001
    9.149873133941222e-002    1.048462471157565e-001

See the documentation on subsref for details.

Rody Oldenhuis
  • 37,726
  • 7
  • 50
  • 96
5

It is a bit of a hack, but here is how you can do it:

data = rand(2,2,3);

eval(['data(' repmat(':,',1,ndims(data)-1) '1)'])

This will give (depending on the randon numbers):

ans =

      0.19255      0.56236
      0.62524      0.90487
Dennis Jaheruddin
  • 21,208
  • 8
  • 66
  • 122
2

You can use shiftdim to bring the last dimension to the first and index that one and reshape it back

x = rand(2,3,4,5,6);

sz = size(x);
A = shiftdim(x, numel(sz)-1);
B = reshape(A(1,:), sz(1:end-1));

and

>> isequal(B, x(:,:,:,:,1))
ans =
     1

or alternatively you can use subsref to index it:

B = subsref(x, substruct('()', [num2cell(repmat(':', 1, ndims(x)-1)) 1]))
Mohsen Nosratinia
  • 9,844
  • 1
  • 27
  • 52
2

Nice question!

Another possibility is to use linear indexing in blocks and then reshape:

x = rand(2,3,4,5); % example data
n = 2; % we want x(:,:,...,:,n)

siz = size(x);
b = numel(x)/siz(end); % block size
result = reshape(x(b*(n-1)+1:b*n),siz(1:end-1));

This seems to be the fastest approach in my computer (but do try yourself; that may depend on Matlab version and system)

Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
1

I think this does it:

a = rand(2,2,2,3)

s = size(a)
r = reshape(a, [], s(end))
reshape(r(:,1), s(1:end-1)) %// reshape(r(:,2), s(1:end-1)) gives you a(:,:,:,...,2) etc...

I benchmarked against Dennis's (correct) answer and it gives the same result but doesn't need eval which is always worth avoiding if possible.

Dan
  • 45,079
  • 17
  • 88
  • 157
0

Just in case GNU Octave readers reach here.

@Rody Oldenhuis's answer can be written as an one-liner in Octave:

> data = reshape(1:8, 2, 2, 2);
> data({':'}(ones(1,ndims(data)-1)){:}, 1)
ans =

   1   3
   2   4

Here:

{':'}(ones(1,ndims(data)-1)){:}

means:

tmp = {':'};
tmp = tmp(ones(1,ndims(data)-1));
tmp{:}

Of couse, repmat({':'},1,ndims(data)-1){:} works also.

Eddy Xiao
  • 273
  • 2
  • 8