Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top