Polyglot
Languages MATLAB indexing
MATLAB § indexing

Indexing and slicing

Indexing in MATLAB is unusually expressive and is the substance of much idiomatic code. Three indexing modes — parenthesis, brace, and dot — apply to different container classes; within parenthesis indexing the language admits linear, subscript, colon, range, end, and logical forms, each with distinct semantics. Indexing on the left-hand side of an assignment is also assignment-into-place: a slice can be read, modified, or deleted by indexing.

One-based, column-major

The first element of an array is A(1). The N-th element is A(N). The last element is A(end). Linear indexing — supplying a single index to a multi-dimensional array — visits elements in column-major order:

A = [1 2 3; 4 5 6];
A(1)         % 1
A(2)         % 4    (next element down the column)
A(3)         % 2    (top of second column)
A(end)       % 6

The one-based convention is consistent with mathematical notation but is the source of conversion bugs in code translated from C or Python; the end keyword removes the most common arithmetic involving array lengths.

Subscript indexing

Multiple comma-separated indices select along each dimension:

A = magic(5);

A(3, 4)              % scalar, element at row 3, col 4
A(2, :)              % the entire second row (1×5)
A(:, 2)              % the entire second column (5×1)
A(2:4, [1 3 5])      % 3×3 subblock

A single colon : matches the whole dimension. A vector of indices selects multiple positions; the result has the dimensions of the index expression along that axis. Indices may repeat: A([1 1 1], :) produces a 3×5 matrix consisting of three copies of the first row.

The keyword end inside an index expression is the index of the last element along the dimension being indexed:

A(end, end)          % bottom-right element
A(end-2:end, :)      % last three rows
A(1:end/2, :)        % first half of the rows

end may participate in arithmetic; the parser evaluates the index expression and substitutes end with the appropriate size.

Linear indexing

A single index applied to a multi-dimensional array is interpreted in column-major order:

A = [1 2 3; 4 5 6];     % 2×3
A(1)                     % 1
A(4)                     % 5
A([1 3 5])               % [1 2 3] (first row read in column-major order)
A(end)                   % 6

The conversion between linear indices and subscripts uses sub2ind and ind2sub:

sub2ind(size(A), 2, 3)       % 6
ind2sub(size(A), 5)          % returns row=1, col=3

Linear indexing is the fastest indexing form and is the basis of much vectorised code.

Logical indexing

A logical array used as an index selects the elements where the index is true. The shape of the result depends on the shape of the source and the index:

x = 1:10;
mask = mod(x, 2) == 0
% 1×10 logical: [0 1 0 1 0 1 0 1 0 1]
x(mask)
% [2 4 6 8 10]

Logical indexing is the idiomatic MATLAB filter. The standard find function returns the linear indices where a logical array is true and is occasionally a clearer alternative:

find(x > 5)              % [6 7 8 9 10]   (the positions)
x(find(x > 5))           % [6 7 8 9 10]   (the values; same as x(x > 5))

The two are equivalent for selection; logical indexing is preferred for clarity, find is preferred when the positions themselves are wanted.

Indexed assignment

The left-hand side of an assignment may be an indexed expression. The right-hand side must have a shape that matches the indexed region:

A = zeros(3, 3);
A(1, :) = [10 20 30];          % set the first row
A(:, 2) = 99;                  % set the second column to 99 (scalar broadcasts)
A(A < 50) = 0;                 % zero everything below 50

The third line is the canonical masked assignment: a logical index on the LHS sets only the selected positions.

A right-hand side of [] deletes the indexed region. The deletion must remove a whole row, column, or slab — partial deletion that would leave a non-rectangular array is an error.

A(:, 2) = []           % delete the second column; A is now 3×2
v = 1:10;
v(3:5) = []            % delete elements 3..5; v becomes [1 2 6 7 8 9 10]

Growth-by-assignment

Assigning past the end of an array grows the array, filling new positions with zeros (or empty strings, for string arrays):

v = [1 2 3];
v(5) = 99
% v = [1 2 3 0 99]

Growth-by-assignment is convenient but slow if performed in a loop; preallocation is preferred (see Matrices and N-d arrays).

Brace indexing into cell arrays

The {} form retrieves the contents of cells; the () form retrieves a smaller cell array:

c = {1, "two", [3 4 5]};
c{2}                   % "two"      (the contents, a string scalar)
c(2)                   % {"two"}    (a 1×1 cell containing the string)
[c{1:2}]               % a comma-separated list; here flattened to [1 "two"]

A comma-separated list expansion is one of MATLAB’s distinctive corners: c{:} produces as many separate values as the cell has elements and is the canonical way to pass a cell of arguments as a variable-length argument list:

args = {0, 2*pi, 100};
linspace(args{:})      % equivalent to linspace(0, 2*pi, 100)

Dot indexing into structs

Field access on a struct uses the dot:

s = struct('name', "Ada", 'birthYear', 1815);
s.name                  % "Ada"
s.birthYear             % 1815

A struct array of length N supports s.name returning a comma-separated list (the principal idiom for “extract the same field from every element”):

arr = struct('x', {1, 2, 3});
[arr.x]                 % [1 2 3]

The dynamic-field form s.(name) permits programmatic access:

fname = "birthYear";
s.(fname)               % 1815

Multi-dimensional struct array indexing

A struct array supports the full indexing grammar — (), (:), end — and dot access. Combining indexed slicing with dot field selection on the result is the source of the most-elaborate indexing expressions in MATLAB:

arr(2:end).x              % comma-separated list of x fields for elements 2..end
{arr(2:end).x}            % the same, gathered into a cell array
[arr(arr.flag).x]         % cannot work this way directly; see arrayfun

The mechanism is rich, occasionally confusing, and best learned by example. The official documentation page on advanced indexingmathworks.com/help/matlab/math/array-indexing.html — is the reference for the corner cases.

The end keyword in detail

end inside an index expression has access to the size of the dimension being indexed. In a 1-d context it is the length; in a multi-d context it depends on the dimension number in the slot. The function size(A, k) is what end reduces to:

A = magic(5);
A(end, 1)              % 5,1
A(1, end)              % 1,5
A(end-1, end-1)        % 4,4
A(end:-1:1, :)         % rows reversed

end may not appear outside of an indexing expression except in the keyword form that terminates if, for, etc.

Indexing into function output

A function’s return value can be indexed directly only when assigned to a temporary — there is no direct f(x)(1) form. The remedy is either an intermediate variable or the subsref/getfield function:

% Common pitfall:
% size(A)(1)              % syntax error in MATLAB

% Remedies:
sz = size(A); sz(1)
size(A, 1)               % most uses are served by an explicit argument

This restriction is the language’s single most-cited vs Octave incompatibility: GNU Octave permits the chained form size(A)(1) and many programs that work in Octave fail to parse in MATLAB.