How to create an empty array of structs?

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 Kommentare

Andrei Bobrov
Andrei Bobrov am 2 Aug. 2011
array=CreateAStruct(1); % The docs imply that this should work
for i=2:n
array(i)=CreateAStruct(i);
end;
Fred Sigworth
Fred Sigworth am 2 Aug. 2011
Yes, exactly. But why can't I start with an empty struct and fill it in, just like I can do with an array, e.g.
vec=[];
for i=1:n
vec(i)=GetValue(i);
end;
Gustavo Delfino
Gustavo Delfino am 4 Okt. 2016
Did you ever find the answer to this question?
Stephen23
Stephen23 am 19 Okt. 2021
Bearbeitet: Stephen23 am 19 Okt. 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

Melden Sie sich an, um zu kommentieren.

 Akzeptierte Antwort

Walter Roberson
Walter Roberson am 2 Aug. 2011

0 Stimmen

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 Kommentare

KAE
KAE am 19 Dez. 2019
Walter, I believe you are thinking of this FEX contribution to "concatenate structs with dissimilar fieldnames by adding empty missing fields".
Walter Roberson
Walter Roberson am 19 Dez. 2019
Not back in 2011 I wasn't; that contribution was 2015. :)
Fred Sigworth
Fred Sigworth am 27 Mai 2020
Thank you! I guess I'll finally have to learn how to use arrayfun and anonymous functions :) but it looks cool.
tommsch
tommsch am 20 Jul. 2020
@Fred No need to learn arrayfun and anonymous functions. Those are magnitudes slower than plain for loops.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (12)

Fernando Freitas Alves
Fernando Freitas Alves am 27 Mai 2020
Bearbeitet: Fernando Freitas Alves am 27 Mai 2020

5 Stimmen

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',[],...);
Philip Borghesani
Philip Borghesani am 13 Jan. 2017

4 Stimmen

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

3 Kommentare

Stephen23
Stephen23 am 12 Jun. 2017
+1 nice and simple. Just make sure that the struct is not defined in the workspace before the loop.
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
Walter Roberson
Walter Roberson am 16 Apr. 2025
parfor starts iterating from the end of the range, so that variables are properly sized from the beginning.

Melden Sie sich an, um zu kommentieren.

Dien Nguyen
Dien Nguyen am 11 Apr. 2018

2 Stimmen

Simple solution, use repmat to "repeat" "n" struct(s) as shown:
array = repmat(struct(field1, [], field2, [], ..., fieldN, []), n);

1 Kommentar

Walter Roberson
Walter Roberson am 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.

Melden Sie sich an, um zu kommentieren.

Sean de Wolski
Sean de Wolski am 2 Aug. 2011

1 Stimme

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 Kommentare

Fred Sigworth
Fred Sigworth am 2 Aug. 2011
Bearbeitet: Walter Roberson am 16 Apr. 2025
Thank you, Sean, your code works. But when I then try to assign the whole larger struct to one element of the array it gives an error:
s.a=1;
s.b=2;
array=([]);
avals=1:10;
for ii=1:10
array(ii).a=avals(ii);
array(ii)=s; % if I leave this line out it works fine.
end;
I want to be able to do this because I want to build up an array (don't know beforehand how many elements) of structs that have 20 or so fields..
From the blog pointed to by Fangjun it's beginning to look like the only way I can do what I want is by crummy code like what I showed initially.
Sean de Wolski
Sean de Wolski am 2 Aug. 2011
why don't you use a cell array of structs?
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.

Melden Sie sich an, um zu kommentieren.

Samuel
Samuel am 3 Dez. 2013

1 Stimme

It's easy. test(10,10) = struct; This creates an 10*10 empty structs.

1 Kommentar

Walter Roberson
Walter Roberson am 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.

Melden Sie sich an, um zu kommentieren.

DAEHO KIM
DAEHO KIM am 5 Apr. 2021

1 Stimme

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 Kommentare

Fred Sigworth
Fred Sigworth am 5 Apr. 2021
Wow, fantastic! Thanks so much.
DAEHO KIM
DAEHO KIM am 6 Apr. 2021
Bearbeitet: DAEHO KIM am 6 Apr. 2021
Thank you.
There is an application version.
% pre-allocate array structure.
array(1: n)= struct;
for iter1= 1: n
array(iter1).a= "anything";
array(iter1).n= "nothing";
% pre-allocate array2 structure in the array structure.
array(iter1).array2(1: m)= struct;
for iter2= 1: m
array(iter1).array2(iter2).e= "everything";
end
end
Stephen23
Stephen23 am 19 Okt. 2021
Bearbeitet: Stephen23 am 19 Okt. 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.

Melden Sie sich an, um zu kommentieren.

David Young
David Young am 21 Jan. 2014

0 Stimmen

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

1 Kommentar

Stephen23
Stephen23 am 25 Jan. 2023
This requires that the structure fields are known in advance, which is not what the question requested.

Melden Sie sich an, um zu kommentieren.

Francesco Onorati
Francesco Onorati am 13 Jan. 2017
Bearbeitet: Francesco Onorati am 13 Jan. 2017

0 Stimmen

array(n)=struct(field1, [], field2, [], ..., fieldN, []); % <-- as CreateAStruct struct
for i:n
array(i)=CreateAStruct(var1(i), var2(i));
end

1 Kommentar

Stephen23
Stephen23 am 19 Okt. 2021
This requires that the structure fields are known in advance, which is not what the question requested.

Melden Sie sich an, um zu kommentieren.

Bruno Luong
Bruno Luong am 20 Jul. 2020
Bearbeitet: Bruno Luong am 20 Jul. 2020

0 Stimmen

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.

1 Kommentar

Anotherway is to use the attached file AllocateStruct with the structure element has identical fileds
for i=1:n
s = myfun(i, var1, var2, etc);
if i == 1 % ~exist('sarray', 'var')
sarray = AllocateStruct(s, [1 n]);
end
sarray(i) = s;
end

Melden Sie sich an, um zu kommentieren.

Owen Claxton
Owen Claxton am 19 Okt. 2021

0 Stimmen

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 Kommentare

Stephen23
Stephen23 am 19 Okt. 2021
Bearbeitet: Stephen23 am 19 Okt. 2021
@Owen Claxton: no, this does not assign a (scalar) structure within the loop, as the original question requires.
Also: square brackets are a concatenation operator, so in your code they are completely superfluous.
Owen Claxton
Owen Claxton am 11 Nov. 2021
Bearbeitet: Owen Claxton am 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

Melden Sie sich an, um zu kommentieren.

Lihan Xie
Lihan Xie am 25 Feb. 2022
Bearbeitet: Lihan Xie am 25 Feb. 2022

0 Stimmen

The most simple way to get the struct array :
array=[];
for i=1:n
st=CreateAStruct(i);
array=[array st];
end
Cameron
Cameron am 15 Apr. 2025

0 Stimmen

Empty_Struct_Array = repmat(struct,0,0)
Empty_Struct_Array = 0x0 empty struct array with no fields.
The simplest solution I can think of... unsure about optimizing computation efficiency, but it's a single line of code.

2 Kommentare

Walter Roberson
Walter Roberson am 16 Apr. 2025
This does not satisfy the original requirement that the struct entry be the result of executing CreateAStruct with argument equal to the index.
Stephen23
Stephen23 am 16 Apr. 2025
Bearbeitet: Stephen23 am 16 Apr. 2025
No, this fails the requirement to be able to allocate a new scalar structure on each loop iteration without knowing their fieldnames in advance. Your untested code fails with exactly the same error as the OP reported fourteen years ago. Lets test it now:
Empty_Struct_Array = repmat(struct,0,0); % Your answer
for k = 1:7
Empty_Struct_Array(k) = CreateAStruct(k)
end
Subscripted assignment between dissimilar structures.

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Data Type Identification finden Sie in Hilfe-Center und File Exchange

Produkte

Community Treasure Hunt

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

Start Hunting!

Translated by