How to create an empty array of structs?

조회 수: 325 (최근 30일)
Fred Sigworth
Fred Sigworth 2011년 8월 2일
댓글: Stephen23 2023년 1월 25일
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
Gustavo Delfino
Gustavo Delfino 2016년 10월 4일
Did you ever find the answer to this question?
Stephen23
Stephen23 2021년 10월 19일
편집: Stephen23 2021년 10월 19일
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

댓글을 달려면 로그인하십시오.

채택된 답변

Walter Roberson
Walter Roberson 2011년 8월 2일
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
Fred Sigworth
Fred Sigworth 2020년 5월 27일
Thank you! I guess I'll finally have to learn how to use arrayfun and anonymous functions :) but it looks cool.
tommsch
tommsch 2020년 7월 20일
@Fred No need to learn arrayfun and anonymous functions. Those are magnitudes slower than plain for loops.

댓글을 달려면 로그인하십시오.

추가 답변 (11개)

Philip Borghesani
Philip Borghesani 2017년 1월 13일
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
Stephen23
Stephen23 2017년 6월 12일
+1 nice and simple. Just make sure that the struct is not defined in the workspace before the loop.
Jeff Miller
Jeff Miller 2018년 1월 25일
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

댓글을 달려면 로그인하십시오.


Fernando Freitas Alves
Fernando Freitas Alves 2020년 5월 27일
편집: Fernando Freitas Alves 2020년 5월 27일
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',[],...);

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

댓글을 달려면 로그인하십시오.


Sean de Wolski
Sean de Wolski 2011년 8월 2일
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
Sean de Wolski
Sean de Wolski 2011년 8월 2일
why don't you use a cell array of structs?
Nathaniel Jones
Nathaniel Jones 2017년 6월 12일
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.

댓글을 달려면 로그인하십시오.


Samuel
Samuel 2013년 12월 3일
It's easy. test(10,10) = struct; This creates an 10*10 empty structs.
  댓글 수: 1
Walter Roberson
Walter Roberson 2018년 4월 11일
This does not satisfy the original requirement that the struct entry be the result of executing CreateAStruct with argument equal to the index.

댓글을 달려면 로그인하십시오.


DAEHO KIM
DAEHO KIM 2021년 4월 5일
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
DAEHO KIM
DAEHO KIM 2021년 4월 6일
편집: DAEHO KIM 2021년 4월 6일
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 2021년 10월 19일
편집: Stephen23 2021년 10월 19일
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.

댓글을 달려면 로그인하십시오.


David Young
David Young 2014년 1월 21일
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
Stephen23
Stephen23 2023년 1월 25일
This requires that the structure fields are known in advance, which is not what the question requested.

댓글을 달려면 로그인하십시오.


Francesco Onorati
Francesco Onorati 2017년 1월 13일
편집: Francesco Onorati 2017년 1월 13일
array(n)=struct(field1, [], field2, [], ..., fieldN, []); % <-- as CreateAStruct struct
for i:n
array(i)=CreateAStruct(var1(i), var2(i));
end
  댓글 수: 1
Stephen23
Stephen23 2021년 10월 19일
This requires that the structure fields are known in advance, which is not what the question requested.

댓글을 달려면 로그인하십시오.


Bruno Luong
Bruno Luong 2020년 7월 20일
편집: Bruno Luong 2020년 7월 20일
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
Bruno Luong
Bruno Luong 2022년 2월 28일
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

댓글을 달려면 로그인하십시오.


Owen Claxton
Owen Claxton 2021년 10월 19일
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
Stephen23
Stephen23 2021년 10월 19일
편집: Stephen23 2021년 10월 19일
@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 2021년 11월 11일
편집: Owen Claxton 2021년 11월 11일
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

댓글을 달려면 로그인하십시오.


Lihan Xie
Lihan Xie 2022년 2월 25일
편집: Lihan Xie 2022년 2월 25일
The most simple way to get the struct array :
array=[];
for i=1:n
st=CreateAStruct(i);
array=[array st];
end

카테고리

Help CenterFile Exchange에서 Structures에 대해 자세히 알아보기

제품

Community Treasure Hunt

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

Start Hunting!

Translated by