Cell and Struct Arrays
Cell arrays are exceptionally flexible data structures provided by MATLAB for handling heterogeneous collections of data. Such data collections are fairly common. For example, you may want to associate a date or descriptive string with each data point. Being able to store both types of data in the same container makes the code easier to read, the relationships between the data easier to understand, and requires fewer arguments when passing the data to other functions.
Using cell arrays is simple. You can declare an empty cell array by executing the command "X=cell(0);", although this is not really necessary since you can just begin assigning entries to X in the same manner as for arrays and matrices. Assign entries to a cell array with the "curly" brace notation; assign the scalar value 1 to the first entry of the cell array X by typing X{1} = 1; The same cell array can have a string assigned to its second entry and an array of scalar values for its third entry.
>> X = cell(0);
>> X{1} = 1;
>> X{2} = 'Hello World';
>> X{3} = [9949 9967 9973];
>> X
>> X =
[1] 'Hello World' [1x3 double]
If you attempt to print the contents of a cell, MATLAB may either print the actual contents or it may print a shorter representation of a given entry, such as the "[1x3 double]" shown in the example above. You can always obtain the full contents of a given entry by accessing it directly, which is also done with the curly brace notation. Finally, cell arrays are also flexible enough to contain other cells, making the combinations of data storage nearly limitless. The curly brace notation actually "stacks", so if Y{1}=X; as in the example above, the second entry of X can be accessed directly by typing Y{1}{2}. Cells can also be easily manipulated within foreign functions using the MEX or matrix API, using for example the 'mxGetCell' function in C, although we do not go into additional detail about that usage in this module.
>> Y{1} = X;
>> Y
Y =
{1x3 cell}
>> Y{1}{2}
ans =
'Hello World'
It is worth pointing out that in some cases you may want to name fields instead of just using cell arrays to contain a heterogeneous array of values; in this case, you could use a struct array (though certainly you could also have a cell array nested in a struct or vice versa); it is even possible to just extract the values of a struct into a cell array using the built-in function struct2cell.
It is better to think of a cell array less as a special kind of array (despite the {}-indexing syntax) and instead as an array of cells, where a cell is just a container that can hold a value of any type. As an example: in MATLAB strings are character arrays, so to get an array of strings, since MATLAB only supports arrays of primitive types or cells we need to create a cell for each character array; in other words, since a character array is a string, a cell array of character arrays is an array of strings.
Struct-arrays, on the other hand,
really do act like specialized arrays, as they can be created from individual fields of arrays,
but a "slice" can be viewed as if it were a single struct. This may be a little confusing,
so let's take a look at some examples. First, another point of confusion: both structs
and struct arrays are created using the built-in struct
function.
Creating an ordinary struct
>> notSA = struct();
>> notSA.baz = [5 6];
>> notSA.foo = [1 2 3]
notSA =
struct with fields:
baz: [5 6]
foo: [1 2 3]
Creating a struct-array and accessing structs within
>> SA = struct([])
SA =
0x0 empty struct array with no fields.
% We can't treat SA as a struct directly:
>> SA.foo = [1 2 3]
A dot name structure assignment is illegal when the structure is empty. Use a subscript on the structure.
>> SA(1).foo = [1 2 3];
>> SA(1).baz = [5 6]
SA =
struct with fields:
foo: [1 2 3]
baz: [5 6]
>> SA(2).baz = [7 8]
SA =
1x2 struct array with fields:
foo
baz
>> SA(1)
ans =
struct with fields:
foo: [1 2 3]
baz: [5 6]
>> SA(2)
ans =
struct with fields:
foo: []
baz: [7 8]
Here we see that the overall struct array has the length of
whatever field is longest (in this case, baz
); other fields will yield
an empty array when the struct array is accessed beyond the field's length
(as with foo
above).
Advanced notes on struct-arrays
We'll briefly
note that you can also assign to a struct array in an indexed fashion,
but by using ()
instead of {}
, just like for numeric arrays.
Unfortunately, creating an empty struct array that can be easily used
for various types can be tricky; []
alone is a double array, and
struct([])
is an empty array of empty structs. We can use cell
intermediates:
% cell array of structs
N = 3;
list = cell(N,1)
for i = 1:N
list{i} = struct('field1',1,'field2',2);
end
% array of structs
list = [list{:}];
We can then inspect to see we have the desired result:
>> list
list =
1x3 struct array with fields:
field1
field2
The preallocation using cell will work even if N > numel(list)
, for
instance, if there is a conditional for assignment in the for
loop.