How to create an empty array of structs?

1,010 views (last 30 days)
I would like to make a loop that accumulates an array of structures, such as
array=struct([]); % The docs imply that this should work
for i=1:n
st=CreateAStruct(i);
array(i)=st;
end;
But...this doesn't work, I get the error, "Subscripted assignment between dissimilar structures." on the first pass through the loop. Instead the only way I've found to do this is the following.
for i=1:n
st=CreateAStruct(i);
if i==1
array=st;
else
array(i)=st;
end;
end;
Is there a nicer way to do this?
  4 Comments
Stephen
Stephen on 19 Oct 2021
Several "Answers" on this thread were written without a clear understanding of the actual problem and task.
As a demonstration and simple test case I wrote this function (below). To keep it simple it must be called in monotonic sequence with step 1 or -1, i.e. either 1, 2, ... N-1, N or N, N-1, ... 2, 1.
% do not attempt to preallocate array
for k = 7:-1:1
array(k) = CreateAStruct(k);
end
display(array)
array = 1×7 struct array with fields:
CUT ARW MMB QFA RUP
array = CreateAStruct(1);
for k = 2:7
array(k) = CreateAStruct(k);
end
display(array)
array = 1×7 struct array with fields:
CAZ YIW IUG UUZ OZT
Simple test function:
function sso = CreateAStruct(itr)
nmf = 5; % number of fields
nmc = 3; % number of characters per fieldname
persistent fnm prv
if isempty(fnm) || abs(itr-prv)~=1
fnm = cellstr(char(randi([65,90],nmf,nmc)));
end
sso = cell2struct(num2cell(rand(nmf,1)),fnm,1);
prv = itr;
end

Sign in to comment.

Accepted Answer

Walter Roberson
Walter Roberson on 2 Aug 2011
You are correct, struct() is a struct with no fields, and that is a distinct structure that is not the same as a structure with any defined fields.
Workaround:
T = arrayfun(@(K) CreateAsStruct(K), 1:n, 'UniformOutput',0);
array = horzcat(T{:});
clear T
Also, if I recall correctly, there is a MATLAB File Exchange contribution to do assignment between dissimilar structures.
  4 Comments
tommsch
tommsch on 20 Jul 2020
@Fred No need to learn arrayfun and anonymous functions. Those are magnitudes slower than plain for loops.

Sign in to comment.

More Answers (11)

Romesh
Romesh on 28 Nov 2013
If you know the fields in advance, you can create a 0x0 struct array WITH fields using the syntax
s = struct('a',{},'b',{})
which returns
s =
0x0 struct array with fields:
a
b
This lets you do things like
x.a = 1;
x.b = 1;
s(end+1) = x;
which otherwise fail with the original error message when the struct is initialised as struct([])
  2 Comments
Walter Roberson
Walter Roberson on 26 Mar 2018
Richard, this does not satisfy the original requirement that the struct entry be the result of executing CreateAStruct with argument equal to the index.

Sign in to comment.


Philip Borghesani
Philip Borghesani on 13 Jan 2017
Actualy the simplest and fastest solution to this problem is to not attempt to create an empty struct. Run the loop backwards to allocate the full structure array on the first loop:
% do not attempt to preallocate array
for i=n:-1:1
array(i)=CreateAStruct(i);
end
  2 Comments
Jeff Miller
Jeff Miller on 25 Jan 2018
Unfortunately this doesn't work with parfor, because its range must be increasing consecutive integers. But this seems OK:
array(n)=CreateAStruct(n);
parfor i=1:n-1
array(i) = CreateAStruct(i)
end

Sign in to comment.


Fernando Freitas Alves
Fernando Freitas Alves on 27 May 2020
Edited: Fernando Freitas Alves on 27 May 2020
Since R2008a, you can do:
array = struct.empty(n,0);
Once you cannot assign dissimilar structs and this struct has no field, this is useless.
A better approach would be:
array(n,1) = struct('field1',[],'field2',[],...);

Sean de Wolski
Sean de Wolski on 2 Aug 2011
st = 1:10;
for ii = 1:10
array(ii).st = st(ii);
end
You need to set the value to a field of the struct since that's how structs are indexed. You could also look into using cell arrays:
doc cell
  3 Comments
Nathaniel Jones
Nathaniel Jones on 12 Jun 2017
Sean, using a cell array of structs results in the following error when attempting to assign structs as elements of the cell array:
Conversion to cell from struct is not possible.
At this point, you might want to use
cell2struct()
to convert from a cell array to an array of structs. However, Romesh's answer is a better option.

Sign in to comment.


Samuel
Samuel on 3 Dec 2013
It's easy. test(10,10) = struct; This creates an 10*10 empty structs.
  1 Comment
Walter Roberson
Walter Roberson on 11 Apr 2018
This does not satisfy the original requirement that the struct entry be the result of executing CreateAStruct with argument equal to the index.

Sign in to comment.


DAEHO KIM
DAEHO KIM on 5 Apr 2021
when I pre-allocate the struct array, I do as follows
array(1: n)= struct;
for iter= 1: n
array(iter).a= "anything"
array(iter).n= "nothing"
end
  3 Comments
Stephen
Stephen on 19 Oct 2021
This requires that the structure fields are known in advance, which is not what the question requested.
Case in point: the output of DIR, whose fields have changed over different MATLAB versions.

Sign in to comment.


David Young
David Young on 21 Jan 2014
For a description of the different kinds of empty structs, and a function that allows you to create each kind easily, see my File Exchange submission emptyStruct

Francesco Onorati
Francesco Onorati on 13 Jan 2017
Edited: Francesco Onorati on 13 Jan 2017
array(n)=struct(field1, [], field2, [], ..., fieldN, []); % <-- as CreateAStruct struct
for i:n
array(i)=CreateAStruct(var1(i), var2(i));
end
  1 Comment
Stephen
Stephen on 19 Oct 2021
This requires that the structure fields are known in advance, which is not what the question requested.

Sign in to comment.


Dien Nguyen
Dien Nguyen on 11 Apr 2018
Simple solution, use repmat to "repeat" "n" struct(s) as shown:
array = repmat(struct(field1, [], field2, [], ..., fieldN, []), n);
  1 Comment
Walter Roberson
Walter Roberson on 11 Apr 2018
This does not satisfy the original requirement that the struct entry be the result of executing CreateAStruct with argument equal to the index.

Sign in to comment.


Bruno Luong
Bruno Luong on 20 Jul 2020
Edited: Bruno Luong on 7 Apr 2021
Been there, done that. The most generic way I deal with such situation is like that using a function CATSTRUCT I have created (attached here).
Usage is typically like this:
cellresult = cell(1,n)
for i=1:n
% do something first
% ...
% call iteration subtask that returns a structure or structure array
cellresult{i} = myfun(i, var1, var2, etc);
% do something else
% ...
end
dim = 2; % whatever elongation of structresult you want to get
structresult = catstruct(dim, cellresult); % function mfiles attached
The function CATSTRUCTS can deal with a list of structures that are all dissimilar, so very generic possible usage. The function MYFUN is allowed to return disimilar structures from iteration to iteration. This of course have some speed penalty when structure are concatenated at the last statement compared to stock functions such as horzcat, vertcat, cat(dim, c{: )).
The solution I propose does not require to know in advance the fieldnames of the structure.
PS: TMW can inspire of my small utilities and include in their next MATLAB releases if they wish.

Owen Claxton
Owen Claxton on 19 Oct 2021
Minimum working example:
struct_array_col = [struct()];
struct_array_row = [struct()];
n_structs = 10;
for i = 1 : n_structs
struct_array_col(i,1).name = num2str(round(rand(1) .* 100, 3));
struct_array_row(i).name = num2str(round(rand(1) .* 100, 3));
end
disp(size(struct_array_col))
disp(size(struct_array_row))
  2 Comments
Owen Claxton
Owen Claxton on 11 Nov 2021
Thanks Stephen, after encounting the problem actually described in the question I realised my error. Leaving my answer up just in case it helps someone. Personally, I went with the preallocation approach as I knew the struct fields (thus I could make an array with similar objects):
section_pieces = struct('type', '', 'slength', 0, 'radius', 0, 'sectionID', 0);
for i = 1 : num_sections
section_pieces(i) = sectionSpec(section_types{i}, section_lengths(i), section_radii(i), i);
% sectionSpec creates a struct with type (char array), slength (int),
% radius (int), sectionID (int) fields using some input arrays
end

Sign in to comment.

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!