MATLAB Answers

Setting multiple fields in an existing structure

144 views (last 30 days)
dandan
dandan on 2 Feb 2018
Edited: Ba Mo on 12 Nov 2019
I feel like this should be simple but I'm new to using structures and can't figure out how to get the syntax right. I would like to set multiple fields in an existing structure, but in a cleaner way than just using:
% create structure with empty fields
pd(i)=struct('x',xvals,'CDF',CDFvals,'H',[],'p',[],'ksstat',[],'cv',[]);
% calculate values to be used in empty fields
[H,p,ksstat,cv]=kstest(xdata,[pd(i).x pd(i).CDF]);
% add values to empty fields
pd(i).H=H;
pd(i).p=p;
pd(i).ksstat=ksstat;
pd(i).cv=cv;
I'm trying to replace the last four lines with something like:
pd(i)=setfield(pd(i),'H',H,'p',p,'ksstat',ksstat,'cv',cv);
But the above throws an error saying inputs must be either cell arrays or character vectors.
What's the correct syntax to do this? Thank you!

Answers (2)

Walter Roberson
Walter Roberson on 3 Feb 2018
It is not possible to assign multiple fields at the same level using setfield. The first input defines the struct to start from, the last input defines the values to be set. Everything between those two defines nesting field names and indices, each defining a subset of the level above. Except for the final parameter, every item after the first must be a character vector or a cell array of index values (could be numeric)

  2 Comments

dandan
dandan on 5 Feb 2018
I see, thank you--I was misunderstanding how setfield was used. Is there a way to do this with a different built-in function?
Walter Roberson
Walter Roberson on 6 Feb 2018
struct2cell() the existing structure array. Append on cells containing the new data. cell2struct() the resulting array with the existing fieldnames together with the new fieldnames.
Note that this is not necessarily efficient at all. I see that struct2cell() is now a built-in function, but in some of the earlier releases, struct2cell() and cell2struct() were simply loops of MATLAB code that did the field access on your behalf -- something to use for convenience but not (at least then) for speed.

Sign in to comment.


Ba Mo
Ba Mo on 12 Nov 2019
Edited: Ba Mo on 12 Nov 2019
if you're willing to enumerate the new fields names and values, just as you did in your example:
pd(i)=setfield(pd(i),'H',H,'p',p,'ksstat',ksstat,'cv',cv);
then i dont think you'd mind creating a new temporary/surrogate structure (which you can erase 2 steps later)
Here's my solution:
1) Create a new temporary cell:
pd_temporary = struct('H',H,'p',p,'ksstat',ksstat,'cv',cv)
2) create this anonymous function, which merges 2 structures with no-common (no duplicate) field names
mergestructs = @(x,y) cell2struct([struct2cell(x);struct2cell(y)],[fieldnames(x);fieldnames(y)]);
3) now your problem is that the fieldnames in pd_temporary already exist in pd(i), so you can't use the new anonymous function 'mergestructs' right away.
a work around is to remove the duplicate fieldnames, but remove them from pd(i), not from pd_temporary
orderfields(mergestructs(rmfield(pd(i),fieldnames(pd_temporary)),pd_temporary),fieldnames(pd(i)));
the "orderfields" is a cosmetic luxury.
Since I'm all crazy about anonymous functions, you can declare this at the beginning of your code and use it over and over
PourStruct2Struct = @(x,y) orderfields(mergestructs(rmfield(y,fieldnames(x)),x),fieldnames(y));
All the fields in the first input (x) must also exist in the structure in the second input (y), otherwise, remfield will throw an error.
you can do this in a one liner, but you'll have to declare pd_temporary multiple times within the same line
Finished code: This solution does NOT require a for loop;
mergestructs = @(x,y) cell2struct([struct2cell(x);struct2cell(y)],[fieldnames(x);fieldnames(y)]);
PourStruct2Struct = @(x,y) orderfields(mergestructs(rmfield(y,fieldnames(x)),x),fieldnames(y));
pd(i) = PourStruct2Struct(struct('H',H,'p',p,'ksstat',ksstat,'cv',cv),pd(i));
Hey MATLAB people, can you give me a job please?

  0 Comments

Sign in to comment.