MATLAB Language Indexing matrices and arrays


Example

MATLAB allows for several methods to index (access) elements of matrices and arrays:

  • Subscript indexing - where you specify the position of the elements you want in each dimension of the matrix separately.
  • Linear indexing - where the matrix is treated as a vector, no matter its dimensions. That means, you specify each position in the matrix with a single number.
  • Logical indexing - where you use a logical matrix (and matrix of true and false values) with the identical dimensions of the matrix you are trying to index as a mask to specify which value to return.

These three methods are now explained in more detail using the following 3-by-3 matrix M as an example:

>> M = magic(3)

ans = 

       8    1    6
       3    5    7
       4    9    2

Subscript indexing

The most straight-forward method for accessing an element, is to specify its row-column index. For example, accessing the element on the second row and third column:

>> M(2, 3)

ans =

      7

The number of subscripts provided exactly matches the number of dimensions M has (two in this example).

Note that the order of subscripts is the same as the mathematical convention: row index is the first. Moreover, MATLAB indices starts with 1 and not 0 like most programming languages.

You can index multiple elements at once by passing a vector for each coordinate instead of a single number. For example to get the entire second row, we can specify that we want the first, second and third columns:

>> M(2, [1,2,3])

ans =

       3    5    7

In MATLAB, the vector [1,2,3] is more easily created using the colon operator, i.e. 1:3. You can use this in indexing as well. To select an entire row (or column), MATLAB provides a shortcut by allowing you just specify :. For example, the following code will also return the entire second row

>> M(2, :)

ans =

       3    5    7

MATLAB also provides a shortcut for specifying the last element of a dimension in the form of the end keyword. The end keyword will work exactly as if it was the number of the last element in that dimension. So if you want all the columns from column 2 to the last column, you can use write the following:

>> M(2, 2:end)

ans =

       5    7

Subscript indexing can be restrictive as it will not allow to extract single values from different columns and rows; it will extract the combination of all rows and columns.

>> M([2,3], [1,3])
ans =

       3    7
       4    2

For example subscript indexing cannot extract only the elements M(2,1) or M(3,3). To do this we must consider linear indexing.

Linear indexing

MATLAB allows you to treat n-dimensional arrays as one-dimensional arrays when you index using only one dimension. You can directly access the first element:

>> M(1)

ans = 

       8

Note that arrays are stored in column-major order in MATLAB which means that you access the elements by first going down the columns. So M(2) is the second element of the first column which is 3 and M(4) will be the first element of the second column i.e.

>> M(4)

ans = 

        1

There exist built-in functions in MATLAB to convert subscript indices to linear indices, and vice versa: sub2ind and ind2sub respectively. You can manually convert the subscripts (r,c) to a linear index by

idx = r + (c-1)*size(M,1)

To understand this, if we are in the first column then the linear index will simply be the row index. The formula above holds true for this because for c == 1, (c-1) == 0. In the next columns, the linear index is the row number plus all the rows of the previous columns.

Note that the end keyword still applies and now refers to the very last element of the array i.e. M(end) == M(end, end) == 2.

You can also index multiple elements using linear indexing. Note that if you do that, the returned matrix will have the same shape as the matrix of index vectors.

M(2:4) returns a row vector because 2:4 represents the row vector [2,3,4]:

>> M(2:4)

ans =

        3    4    1

As an other example, M([1,2;3,4]) returns a 2-by-2 matrix because [1,2;3,4] is a 2-by-2 matrix as well. See the below code to convince yourself:

>> M([1,2;3,4])

ans =

       8        3
       4        1

Note that indexing with : alone will always return a column vector:

>> M(:)

ans = 

        8
        3
        4
        1
        5
        9
        6
        7
        2

This example also illustrates the order in which MATLAB returns elements when using linear indexing.

Logical indexing

The third method of indexing is to use a logical matrix, i.e. a matrix containing only true or false values, as a mask to filter out the elements you don't want. For example, if we want to find all the elements of M that are greater than 5 we can use the logical matrix

>> M > 5

ans =

    1    0    1
    0    0    1
    0    1    0

to index M and return only the values that are greater than 5 as follows:

>> M(M > 5)

ans =

        8
        9
        6
        7

If you wanted these number to stay in place (i.e. keep the shape of the matrix), then you could assign to the logic compliment

>> M(~(M > 5)) = NaN

ans = 

    8      NaN    6
    NaN    NaN    7
    NaN    9      Nan

We can reduce complicated code blocks containing if and for statements by using logical indexing.

Take the non-vectorized (already shortened to a single loop by using linear indexing):

for elem = 1:numel(M)
  if M(elem) > 5
    M(elem) = M(elem) - 2;
  end
end

This can be shortened to the following code using logical indexing:

idx = M > 5;
M(idx) = M(idx) - 2;

Or even shorter:

M(M > 5) = M(M > 5) - 2;

More on indexing

Higher dimension matrices

All the methods mentioned above generalize into n-dimensions. If we use the three-dimensional matrix M3 = rand(3,3,3) as an example, then you can access all the rows and columns of the second slice of the third dimension by writing

>> M(:,:,2)

You can access the first element of the second slice using linear indexing. Linear indexing will only move on to the second slice after all the rows and all the columns of the first slice. So the linear index for that element is

>> M(size(M,1)*size(M,2)+1)

In fact, in MATLAB, every matrix is n-dimensional: it just happens to be that the size of most of the other n-dimensions are one. So, if a = 2 then a(1) == 2 (as one would expect), but also a(1, 1) == 2, as does a(1, 1, 1) == 2, a(1, 1, 1, ..., 1) == 2 and so on. These "extra" dimensions (of size 1), are referred to as singleton dimensions. The command squeeze will remove them, and one can use permute to swap the order of dimensions around (and introduce singleton dimensions if required).

An n-dimensional matrix can also be indexed using an m subscripts (where m<=n). The rule is that the first m-1 subscripts behave ordinarily, while the last (m'th) subscript references the remaining (n-m+1) dimensions, just as a linear index would reference an (n-m+1) dimensional array. Here is an example:

>> M = reshape(1:24,[2,3,4]);
>> M(1,1)
ans =
     1
>> M(1,10)
ans =
    19
>> M(:,:)
ans =
     1     3     5     7     9    11    13    15    17    19    21    23
     2     4     6     8    10    12    14    16    18    20    22    24

Returning ranges of elements

With subscript indexing, if you specify more than one element in more than one dimension, MATLAB returns each possible pair of coordinates. For example, if you try M([1,2],[1,3]) MATLAB will return M(1,1) and M(2,3) but it will also return M(1,3) and M(2,1). This can seem unintuitive when you are looking for the elements for a list of coordinate pairs but consider the example of a larger matrix, A = rand(20) (note A is now 20-by-20), where you want to get the top right hand quadrant. In this case instead of having to specify every coordinate pair in that quadrant (and this this case that would be 100 pairs), you just specify the 10 rows and the 10 columns you want so A(1:10, 11:end). Slicing a matrix like this is far more common than requiring a list of coordinate pairs.

In the event that you do want to get a list of coordinate pairs, the simplest solution is to convert to linear indexing. Consider the problem where you have a vector of column indices you want returned, where each row of the vector contains the column number you want returned for the corresponding row of the matrix. For example

colIdx = [3;2;1]

So in this case you actually want to get back the elements at (1,3), (2,2) and (3,1). So using linear indexing:

>> colIdx = [3;2;1];
>> rowIdx = 1:length(colIdx);
>> idx = sub2ind(size(M), rowIdx, colIdx);
>> M(idx)

ans = 

        6    5    4

Returning an element multiple times

With subscript and linear indexing you can also return an element multiple times by repeating it's index so

>> M([1,1,1,2,2,2])

ans = 

        8    8    8    3    3    3

You can use this to duplicate entire rows and column for example to repeat the first row and last column

>> M([1, 1:end], [1:end, end])

ans = 

        8    1    6    6 
        8    1    6    6
        3    5    7    7
        4    9    2    2

For more information, see here.