Structures
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
Written against MATLAB R2026b. The sessions below were run in GNU Octave 11.3.0 (MATLAB code that Octave also accepts) and show Octave’s output; MATLAB displays structures in a different layout (struct with fields:). Where an error message is quoted from MATLAB it is labelled "not run here" or described rather than quoted, because messages vary between releases and Octave’s differ.
A structure groups related values under names called fields. Where a cell array (Cell Arrays) is accessed by position, a structure is accessed by name, which makes code that handles records readable: plate.nx says more than c{4}. Each field can hold any type and size, including another structure. A structure array holds several structures that share the same field names, one per element. Structures are the natural representation of configuration, of the output of jsondecode and readstruct, and of a record that you pass between functions.
Scalar structures
Dot notation creates a structure and its fields on assignment; there is no declaration step.
s.name = 'plate1';
s.size = [10 5];
s.bc.left = 100;
s.bc.right = 0;
s
fieldnames(s)
Octave 11.3.0 output:
s =
scalar structure containing the fields:
name = plate1
size =
10 5
bc =
scalar structure containing the fields:
left = 100
right = 0
ans =
{
[1,1] = name
[2,1] = size
[3,1] = bc
}
The variable s is a scalar structure (a 1-by-1 structure array). The field bc holds a nested structure, reached with a second dot: s.bc.left is 100. If a field holds an array, ordinary indexing applies to the result, as in s.size(2), which is 5. The documentation’s Structure Arrays page builds the same idea with a patient structure whose fields are a name, a billing amount and a 3-by-3 matrix of test results.
You can also create a structure in one call with the function struct:
s = struct(field1, value1, field2, value2, ...)
Field names must begin with a letter and may contain letters, digits and underscores; they are case sensitive and cannot contain periods. Do not reuse the names of existing variables or functions as field names, to avoid confusion.
Dynamic field names
When the field name is only known at run time, wrap an expression in parentheses after the dot. The expression must return a character vector or a string scalar.
f = 'size';
s.(f)
s.(['n' 'ame'])
Octave 11.3.0 output: the first line prints 10 5 and the second prints ans = plate1. The same form creates a field (s.(name) = value) and works with a loop over a list of names, which replaces numbered variables such as plate1, plate2. A name built from user data, for example a sensor identifier, is only legal if it is a valid field name; matlab.lang.makeValidName turns arbitrary text into one. For lookup by arbitrary keys a dictionary is a better fit (Dictionaries and containers.Map).
Inspecting and changing the fields
| Function | Purpose |
|---|---|
|
Cell column of the field names |
|
True if |
|
True if |
|
Returns the structure without that field (a name or a cell array of names) |
|
Returns the structure with fields in alphabetical order (a second argument gives another order) |
|
Function forms of reading and writing a field; dot notation is shorter, but the functions help in code that builds the path as data |
|
Convert between a structure and a cell array of values |
isfield(s, 'name')
isfield(s, {'name','nope','bc'})
s = rmfield(s, 'size');
fieldnames(s)'
t = struct('b',1,'a',2,'c',3);
t2 = orderfields(t);
fieldnames(t2)'
Octave 11.3.0 output: ans = 1, then 1 0 1, then the names name and bc after size is removed, and finally a, b, c for the reordered structure. rmfield fails if the field does not exist, so test with isfield first when it may be absent. The order of the fields is the order of creation, and it matters for display, for struct2cell and when you concatenate structures.
Structure arrays
Indexing a structure variable with a subscript creates an array. Each element is a structure with the same set of fields.
p(1).id = 1; p(2).id = 2; p(3).id = 3;
size(p)
[p.id]
[p.val] = deal(10,20,30);
{p.val}
ids = arrayfun(@(e) e.id*2, p)
Octave 11.3.0 output:
ans =
1 3
ans =
1 2 3
ans =
{
[1,1] = 10
[1,2] = 20
[1,3] = 30
}
ids =
2 4 6
Assigning to p(2).id when p does not exist creates p as a 1-by-2 array and gives the other elements empty fields. Three idioms matter:
-
Gather a field.
p.idwith a structure array is a comma-separated list (Comma-Separated Lists), so[p.id]concatenates the values into an array and{p.id}collects them in a cell array. -
Assign a field of every element.
[p.val] = deal(10,20,30)writes one value per element, and[p.val] = deal(0)the same value everywhere. -
Apply a function per element.
arrayfun(func, p)callsfuncon each element (each is a scalar structure); likecellfunit needsUniformOutputset to false when the results are not scalars.
Deleting an element uses p(2) = [], as for any array, and numel(p) counts the elements. Elements added later by p(end+1) = newElement must have the same fields in the same order.
The struct cell-value trap
The function struct treats a cell array given as a value as a request to create a structure array, one element per cell. This surprises people who want a cell array as the content of a single field.
u = struct('a', {1,2,3});
size(u)
w = struct('a', {{1,2,3}});
size(w)
class(w.a)
z = struct('a', {});
size(z)
Octave 11.3.0 output: size(u) is 1 3 (three elements, each with a a number), size(w) is 1 1 (one element, whose field a is the cell array {1,2,3}, and class(w.a) is cell), and size(z) is 0 0, an empty structure array that still has the field a. To store a cell array in a field, wrap it in a second pair of braces; to make an empty array that has fields but no elements, pass {} as the value. If several values are cells they must have the same size, otherwise struct fails (Octave 11.3.0: struct: dimensions of parameter 2 do not match those of parameter 4; MATLAB raises an error with its own text, not run here); a value that is not a cell is copied to every element.
Source: MATLAB documentation: struct
Applying functions to fields: structfun
structfun applies a function to every field of a scalar structure, as cellfun does for cells.
st.x = 1; st.y = 2; st.z = 3;
structfun(@(v) v*10, st)
r = structfun(@(v) v*10, st, UniformOutput=false)
c = struct2cell(st)
Octave 11.3.0 output (run with the equivalent pair 'UniformOutput', false, because Octave does not accept the Name=Value form): a column 10 20 30; then r as a structure with fields x, y, z equal to 10, 20, 30; and c as a 3-by-1 cell array 1, 2, 3. By default the outputs of structfun are collected into a column vector, which needs scalar results; with UniformOutput set to false the result has the same field names as the input.
Heatflow: the plate configuration from JSON
The plate configuration of the heatflow scenario (The heatflow scenario) lives in plate.json. The function jsondecode turns a JSON object into a scalar structure, a JSON object with equal keys inside an array into a structure array (when all the elements have the same fields), and nested objects into nested structures.
txt = '{"width":0.5,"height":0.3,"nx":50,"ny":30,"boundary":{"left":100,"right":0},"sensors":[{"id":"S1","x":0.1,"y":0.1},{"id":"S2","x":0.4,"y":0.2}]}';
plate = jsondecode(txt);
plate.boundary.left
size(plate.sensors)
plate.sensors(2).id
for k = 1:numel(plate.sensors)
fprintf('%s at (%.1f, %.1f)\n', plate.sensors(k).id, plate.sensors(k).x, plate.sensors(k).y);
end
Octave 11.3.0 output:
ans = 100
ans =
2 1
ans = S2
S1 at (0.1, 0.1)
S2 at (0.4, 0.2)
The sensors become a 2-by-1 structure array, each element carrying id, x and y, and the loop walks it by index. The shape of the array (a column) is what jsondecode produces for an array of objects, and jsonencode reverses the conversion. In a file-based version, plate = jsondecode(fileread("plate.json")) reads the configuration, and readstruct reads JSON or XML directly (the function dates from R2020b, when it read XML; JSON support was added in R2023b) (see JSON, XML and Web Access; not run here). Both functions and jsonencode are in base MATLAB.
Structure, table or object?
| Container | Use when |
|---|---|
Structure |
A fixed set of named values for one record or a handful of records: configuration, options, a function’s multiple related results. Fields have different types and sizes; there is no per-column validation. |
Structure array |
Many records of the same shape that you loop over or gather fields from. Row filtering and grouping are manual. |
Table |
Tabular data with named columns of equal length, filtering, sorting, grouping and joining (Tables). |
Object (class) |
Data that needs behaviour, validation of every assignment, defaults and invariants (classdef Basics). The heatflow |
Common errors
-
Referencing a field that does not exist.
s.bwhereshas no fieldbfails with the identifierMATLAB:nonExistentField(the message says the field does not exist; exact wording varies by release, not run here). Octave 11.3.0 printsstructure has no member 'b'with the identifierOctave:invalid-indexing. Guard optional fields withisfield, or use a default:if isfield(s,'b'), v = s.b; else, v = 0; end. -
Using a list as a value. With
pa 1-by-2 structure array,v = p.idreceives a comma-separated list. Octave 11.3.0 assigns the first value (1) without complaint; MATLAB also keeps a single value, and the behaviour hides the mistake (not run here). Use[p.id]orp(1).idto say what you mean. -
Concatenating structures with different fields.
[a b]whereahas onlyxandbonlyyfails, because a structure array needs the same field names in every element (Octave 11.3.0 printedcat: field names mismatch in concatenating structs; MATLAB raises an error with its own text, not run here). -
The cell-value trap above, when
struct('a', {...})builds an array you did not intend. -
Case.
s.Nameands.nameare different fields. -
Assigning a field of a non-structure. If
xalready holds a number,x.a = 1is an error; clear the variable or initialise withx = struct().
Where older books differ
Books for MATLAB 5 to 7 introduce structures with struct, getfield, setfield and fieldnames, and dynamic field names with the same s.(name) form. The mechanics have not changed. What is newer: jsondecode and jsonencode (R2016b) and readstruct/writestruct (see JSON, XML and Web Access for the release in which they arrived) read and write structures from files; tables (R2013b) cover record collections that older code stored as structure arrays; and the arguments block (R2019b) validates structure inputs through options.Name fields.