What are some efficient ways to combine two structures in MATLAB? - matlab

I want to combine two structures with differing fields names.
For example, starting with:
A.field1 = 1;
A.field2 = 'a';
B.field3 = 2;
B.field4 = 'b';
I would like to have:
C.field1 = 1;
C.field2 = 'a';
C.field3 = 2;
C.field4 = 'b';
Is there a more efficient way than using "fieldnames" and a for loop?
EDIT: Let's assume that in the case of field name conflicts we give preference to A.

Without collisions, you can do
M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)'];
C=struct(M{:});
And this is reasonably efficient. However, struct errors on duplicate fieldnames, and pre-checking for them using unique kills performance to the point that a loop is better. But here's what it would look like:
M = [fieldnames(A)' fieldnames(B)'; struct2cell(A)' struct2cell(B)'];
[tmp, rows] = unique(M(1,:), 'last');
M=M(:, rows);
C=struct(M{:});
You might be able to make a hybrid solution by assuming no conflicts and using a try/catch around the call to struct to gracefully degrade to the conflict handling case.

Short answer: setstructfields (if you have the Signal Processing Toolbox).
The official solution is posted by Loren Shure on her MathWorks blog, and demonstrated by SCFrench here and in Eitan T's answer to a different question. However, if you have the Signal Processing Toolbox, a simple undocumented function does this already - setstructfields.
help setstructfields
setstructfields Set fields of a structure using another structure
setstructfields(STRUCTIN, NEWFIELDS) Set fields of STRUCTIN using
another structure NEWFIELDS fields. If fields exist in STRUCTIN
but not in NEWFIELDS, they will not be changed.
Internally it uses fieldnames and a for loop, so it is a convenience function with error checking and recursion for fields that are themselves structs.
Example
The "original" struct:
% struct with fields 'color' and 'count'
s = struct('color','orange','count',2)
s =
color: 'orange'
count: 2
A second struct containing a new value for 'count', and a new field, 'shape':
% struct with fields 'count' and 'shape'
s2 = struct('count',4,'shape','round')
s2 =
count: 4
shape: 'round'
Calling setstructfields:
>> s = setstructfields(s,s2)
s =
color: 'orange'
count: 4
shape: 'round'
The field 'count' is updated. The field 'shape' is added. The field 'color' remains unchanged.
NOTE: Since the function is undocumented, it may change or be removed at any time.

I have found a nice solution on File Exchange: catstruct.
Without testing the performance I can say that it did exactly what I wanted.
It can deal with duplicate fields of course.
Here is how it works:
a.f1 = 1;
a.f2 = 2;
b.f2 = 3;
b.f4 = 4;
s = catstruct(a,b)
Will give
s =
f1: 1
f2: 3
f3: 4

I don't think you can handle conflicts well w/o a loop, nor do I think you'd need to avoid one. (although I suppose efficiency could be an issue w/ many many fields...)
I use a function I wrote a few years back called setdefaults.m, which combines one structure with the values of another structure, where one takes precedence over the other in case of conflict.
% SETDEFAULTS sets the default structure values
% SOUT = SETDEFAULTS(S, SDEF) reproduces in S
% all the structure fields, and their values, that exist in
% SDEF that do not exist in S.
% SOUT = SETDEFAULTS(S, SDEF, OVERRIDE) does
% the same function as above, but if OVERRIDE is 1,
% it copies all fields of SDEF to SOUT.
function sout = setdefaults(s,sdef,override)
if (not(exist('override','var')))
override = 0;
end
sout = s;
for f = fieldnames(sdef)'
cf = char(f);
if (override | not(isfield(sout,cf)))
sout = setfield(sout,cf,getfield(sdef,cf));
end
end
Now that I think about it, I'm pretty sure that the "override" input is unnecessary (you can just switch the order of the inputs) though I'm not 100% sure of that... so here's a simpler rewrite (setdefaults2.m):
% SETDEFAULTS2 sets the default structure values
% SOUT = SETDEFAULTS(S, SDEF) reproduces in S
% all the structure fields, and their values, that exist in
% SDEF that do not exist in S.
function sout = setdefaults2(s,sdef)
sout = sdef;
for f = fieldnames(s)'
sout = setfield(sout,f{1},getfield(s,f{1}));
end
and some samples to test it:
>> S1 = struct('a',1,'b',2,'c',3);
>> S2 = struct('b',4,'c',5,'d',6);
>> setdefaults2(S1,S2)
ans =
b: 2
c: 3
d: 6
a: 1
>> setdefaults2(S2,S1)
ans =
a: 1
b: 4
c: 5
d: 6

In C, a struct can have another struct as one of it's members. While this isn't exactly the same as what you're asking, you could end up either with a situation where one struct contains another, or one struct contains two structs, both of which hold parts of the info that you wanted.
psuedocode: i don't remember the actual syntax.
A.field1 = 1;
A.field2 = 'a';
A.field3 = struct B;
to access:
A.field3.field4;
or something of the sort.
Or you could have struct C hold both an A and a B:
C.A = struct A;
C.B = struct B;
with access then something like
C.A.field1;
C.A.field2;
C.B.field3;
C.B.field4;
hope this helps!
EDIT: both of these solutions avoid naming collisions.
Also, I didn't see your matlab tag. By convention, you should want to edit the question to include that piece of info.

Related

How to make a Matlab structure constant once it is already created?

Suppose I have a function defined in foo.m. This function can take a parameter thing of type struct. Once foo makes changes to thing, I want to "lock" thing so that it can no longer be changed. I essentially want to make it constant. I want to do this to ensure it isn't modified further down the line. How do I do this in Matlab?
You should
define the variable in the function to be persistent
lock your function in the memory using mlock.
mlock locks the currently running function in memory so that subsequent clear functions do not remove it. Locking a function in memory also prevents any persistent variables defined in the file from getting reinitialized.
Solution 1: Good if you don't know what form your struct will have in advance
You could 'capture' that variable with an anonymous function handle and only refer to your structure with that from now on. An anonymous function handle captures the state of the workspace at the time it is created. You will be able to access its elements as if it were the original struct, but if you try to assign to it, you'll generate an error.
E.g.
>> S_.a = 1;
>> S_.b = 2;
>> S = #() S_;
>> S_.a = 3;
>> S_
S_ =
scalar structure containing the fields:
a = 3
b = 2
>> S()
ans =
scalar structure containing the fields:
a = 1
b = 2
It's almost identical in syntax, except for the annoyance that you'll have to call it with ().
I've used it on the terminal here, but obviously it can easily also be used in the context of a function.
Small caveat; if you redefine and overwrite the anonymous function, obviously, this backfires, since it will inherit whatever new workspace it had access to at the time of the redefinition.
Solution 2: Good if you know your struct's form in advance:
Assume you know in advance that your struct will only contain fields a and b. Create a class with the same properties restricting 'SetAccess', e.g.
classdef ConstStruct
properties (GetAccess = 'public', SetAccess = 'private')
a
b
end
methods
%constructor
function obj = ConstStruct(S)
obj.a = S.a;
obj.b = S.b;
end
end
end
Then in your main code:
>> MyStruct = struct('a',1,'b',2)
MyStruct =
a: 1
b: 2
>> MyStruct = ConstStruct(MyStruct)
MyStruct =
ConstStruct with properties:
a: 1
b: 2
>> MyStruct.a
ans =
1
>> MyStruct.a = 2
You cannot set the read-only property 'a' of 'ConstStruct'.

Dynamically assign structure field name with hierarchy

I would like to be able to dynamically assign fields to a structure array, including hierarchy, in MATLAB (r2014a). I'm not sure how best to describe the problem except through the following example.
I know how to do this:
field_name1 = 'bar1';
field_name2 = 'bar2';
% ... etc.
foo.(field_name1) = pi;
foo.(field_name2) = exp(1);
% ... etc.
results in a structure variable foo with fields bar1 and bar2.
What I would like to be able to do is this:
field_name1 = 'bar1';
field_name2 = 'bar2';
% ... etc.
if true_false_statement
extra_level = '';
else
extra_level = 'baz.';
end
foo.([extra_level field_name1]) = pi;
foo.([extra_level field_name2]) = exp(1);
% ... etc.
where depending on a previous condition, the fields can be stored either in the top level of the structure or else under a sub-field.
(Note that if I was doing this from scratch, I would design things differently to avoid this problem. However, I am modifying some code that is the middle step in a much larger workflow, so I have to keep the data structure consistent.)
Currently, the code looks something like this:
field_name1 = 'bar1';
field_name2 = 'bar2';
% ... etc.
if true_false_statement
foo.(field_name) = pi;
foo.(field_name) = exp(1);
% ... etc.
else
foo.baz.(field_name) = pi;
foo.baz.(field_name) = exp(1);
% ... etc.
end
Perhaps fine for one or two field, but there are a lot of fields, which results in a lot of copy/pasted code. I have tried making extra_level an empty field, and I have tried making field_name of the form *.* as above, but both options throw an error because the result is not a valid variable name.
Is there a good way to do this?
The simplest manner I can think of to achieve your desired use (the middle block of code) is to use setfield (which is mostly a wrapper for subsasgn these days) and the fact that an empty cell array expands to nothing (something I've answered about in the past and what I like to call a feature):
>> foo = struct();
>> extra_level = {};
>> foo = setfield(foo,extra_level{:},'bar1',1)
foo =
bar1: 1
>> extra_level = {'baz'};
>> foo = setfield(foo,extra_level{:},'bar2',2)
foo =
bar1: 1
baz: [1x1 struct]
>> foo.baz.bar2
ans =
2

Nested structure access using dynamic fieldnames

I'd like to achieve the following using dynamic fieldnames instead of setfield:
Say a struct 'myStruct' has a set of nested structures, i.e.
myStruct.a.b.c = 0
myStruct.a.d = 0
myStruct.a.e.f.g = 0
I want to be able to flexibly set the leaf structure values as follows:
fields = {'a', 'b', 'c'}
paramVal = 1
setfield(myStruct, fields{:}, paramVal)
This works using setfield. Is there a syntax that will do this using dynamic fieldnames? The following obviously doesn't work because the fieldname needs to be a string not an array, but demonstrates what I want:
myStruct.(fields{:}) = 0
Which would be equivalent to:
myStruct.('a').('b').('c') = 0
Recursive solution without eval, ripped from one of my old utility functions:
function s = setsubfield(s, fields, val)
if ischar(fields)
fields = regexp(fields, '\.', 'split'); % split into cell array of sub-fields
end
if length(fields) == 1
s.(fields{1}) = val;
else
try
subfield = s.(fields{1}); % see if subfield already exists
catch
subfield = struct(); % if not, create it
end
s.(fields{1}) = setsubfield(subfield, fields(2:end), val);
end
I guess the try/catch can be replaced with if isfield(s, fields{1}) ..., I don't remember why I coded it like that.
Usage:
>> s = struct();
>> s = setsubfield(s, {'a','b','c'}, 55);
>> s = setsubfield(s, 'a.b.d.e', 12)
>> s.a.b.c
ans =
55
>> s.a.b.d.e
ans =
12
Below is a simple, if crude, solution that works for scalar structs. Applying it to your example,
S=setfld(myStruct,'a.b.c',1)
>> S.a.b.c
ans =
1
In general, though, deeply nested structs are unrecommended.
function S=setfld(S,fieldpath,V)
%A somewhat enhanced version of setfield() allowing one to set
%fields in substructures of structure/object S by specifying the FIELDPATH.
%
%Usage: setfld(S,'s.f',V) will set S.s.f=V
%
%
%%Note that for structure S, setfield(S.s,'f') would crash with an error if
%S.s did not already exist. Moreover, it would return a modified copy
%of S.s rather than a modified copy of S, behavior which would often be
%undesirable.
%
%
%Works for any object capable of a.b.c.d ... subscripting
%
%Currently, only single structure input is supported, not structure arrays.
try
eval(['S.' fieldpath '=V;']);
catch
error 'Something''s wrong.';
end

MATLAB -> struct.field(1:end).field?

Is there a way that I get all the structure subsubfield values of a subfield in one line ? Something like this :
struct.field(1:end).field
If I understand your question aright, you want to collect all the fields of the second-level structure, with the name 'field', into a single output array. It doesn't quite meet your request for a one-liner, but you can do it like this:
a.field1.a = 1;
a.field1.b = 2;
a.field2.a = 3;
a.field2.b = 4;
result = [];
for x = fieldnames(a)'
result = horzcat(result, a.(x{:}).a);
end
The ending value of result is [1 3]
Simple Structure Example
aStruct.subField = struct('subSubField', {1;2;3;4})
So that
aStruct.subField(1).subSubField == 1
aStruct.subField(1).subSubField == 2
Etc. Then the values of the leaf nodes can be obtained via a one-liner as
valueLeafs = [aStruct.subField.subSubField];
Which can be checked via assert(all(valueLeafs == [1,2,3,4])).
Non-Scalar Structure Example
The above one-liner also works when the leaf node values are non-scalar such that they can be horizontally concatenated. For example
bStruct.subField = struct('subSubField', {[1,2];[3,4]})
valueLeafs_b = [bStruct.subField.subSubField]; % works okay
cStruct.subField = struct('subSubField', {[1,2];[3;4]})
valueLeafs_c = [cStruct.subField.subSubField]; % error: bad arg dims
Distinct Class Structure Example
The one-line solution given previously does not work whenever the leaf node values are different class since they cannot - in general, be concatenated. However, use of arrayfun and a tricky anonymous function typically provide the required indexing technique:
dStruct.subField = struct('subSubField', {[1;2];'myString'});
valueLeafs_d = arrayfun(#(x) x.subSubField, dStruct.subField, 'UniformOutput', false)

How can I count the number of properties in a structure in MATLAB?

I have a function that returns one or more variables, but as it changes (depending on whether the function is successful or not), the following does NOT work:
[resultA, resultB, resultC, resultD, resultE, resultF] = func(somevars);
This will sometimes return an error, varargout{2} not defined, since only the first variable resultA is actually given a value when the function fails. Instead I put all the output in one variable:
output = func(somevars);
However, the variables are defined as properties of a struct, meaning I have to access them with output.A. This is not a problem in itself, but I need to count the number of properties to determine if I got the proper result.
I tried length(output), numel(output) and size(output) to no avail, so if anyone has a clever way of doing this I would be very grateful.
length(fieldnames(output))
There's probably a better way, but I can't think of it.
It looks like Matthews answer is the best for your problem:
nFields = numel(fieldnames(output));
There's one caveat which probably doesn't apply for your situation but may be interesting to know nonetheless: even if a structure field is empty, FIELDNAMES will still return the name of that field. For example:
>> s.a = 5;
>> s.b = [1 2 3];
>> s.c = [];
>> fieldnames(s)
ans =
'a'
'b'
'c'
If you are interested in knowing the number of fields that are not empty, you could use either STRUCTFUN:
nFields = sum(~structfun(#isempty,s));
or a combination of STRUCT2CELL and CELLFUN:
nFields = sum(~cellfun('isempty',struct2cell(s)));
Both of the above return an answer of 2, whereas:
nFields = numel(fieldnames(s));
returns 3.