Reputation: 8467
Growing an array, e.g. through x = [x, a]
in a loop, is usually frowned upon in Matlab programming, because it leads to one or more resize operations, and therefore preallocation is usually the better option. However, in some contexts, for example as a reduction assignment in a parfor
block, it can have advantages. For that purpose, the array has to be created as zero-size. For numerical arrays, the expression for that is []
, for cell arrays {}
.
For struct arrays, it is not so clear cut. For example initialization as struct()
does not create a zero-size struct array, but a 1x1 struct array with no fields. This leads to the error
Error using horzcat
Number of fields in structure arrays being concatenated do not match.
Concatenation of structure arrays requires that these arrays have the same set of fields.
while growing, because the field structure of appended structs is incompatible with the "no fields" struct.
How to initialize a zero-size struct array for growing?
Upvotes: 3
Views: 3045
Reputation: 8467
It turns out the answer is to initialize to a zero-size numeric array, x = []
. Even though it is not a struct array, appending a struct a
via x = [x, a]
generates a 1x1 struct array, to which further structs with the same fields can be appended.
This unintuitive behavior seems to be a general quirk of the Matlab language, in that []
is of "flexible type". It is initially a zero-size array of doubles, but appending singles makes it a single array, and appending cell arrays makes it a cell array.
As @LuisMendo pointed out in the comments, struct([])
directly gives a zero-size struct array with no fields. This syntax may be preferred because it is less ambiguous. Moreover, s = struct('field1', {}, 'field2', {})
may be used to create a zero-size struct array with defined fields.
I just found that @CrisLuengo's proposal in the comments, appending by assignment to end + 1
instead of concatenation, does not work in the context of the question, "initialize for growing". Assignment cannot change the "type" of the struct, which is defined by its fields. Changing from no fields to the fields of whatever struct is to be appended leads to the error "Subscripted assignment between dissimilar structures."
(but see his comment and my answer for clarification)
Upvotes: 2
Reputation: 60444
Growing an array by concatenation
x = [x, 0];
is very slow, see here and here. Instead, one should (if pre-allocation is not possible for whatever reason), grow an array by appending a new element like so:
x(end+1) = 0;
The reason is that [x,0]
creates a new array, copying the old data into it, at every single loop iteration, whereas the other form extends the array, needing reallocation only occasionally (it doubles the underlying memory size when the array becomes too small).
To initialize an empty struct array (as suggested by @LuisMendo in a comment) one can do this:
s = struct('field1', {}, 'field2', {});
To append to it, do:
s(end+1) = struct('field1', 1, 'field2', 'x');
Alternatively, one can append by
s(end+1).field1 = 5;
s(end).field2 = 'y';
Note that in this case, end+1
only happens when first appending a new element to the array, subsequent fields are written to the last array element.
Upvotes: 2