**Editor's Note:** This file was selected as MATLAB Central Pick of the Week

CATSTRUCT Concatenate or merge structures with different fieldnames

X = CATSTRUCT(S1,S2,S3,...) merges the structures S1, S2, S3 ... into one new structure X. X contains all fields present in the various

structures. An example:

A.name = 'Me' ;

B.income = 99999 ;

X = catstruct(A,B)

% -> X.name = 'Me' ;

% X.income = 99999 ;

If a fieldname is not unique among structures (i.e., a fieldname is present in more than one structure), only the value from the last structure with this field is used. In this case, the fields are alphabetically sorted. A warning is issued as well. An axample:

S1.name = 'Me' ;

S2.age = 20 ; S3.age = 30 ; S4.age = 40 ;

S5.honest = false ;

Y = catstruct(S1,S2,S3,S4,S5) % use value from S4

The inputs can be array of structures. All structures should have the same size. An example:

C(1).bb = 1 ; C(2).bb = 2 ;

D(1).aa = 3 ; D(2).aa = 4 ;

CD = catstruct(C,D) % CD is a 1x2 structure array with fields bb and aa

The last input can be the string 'sorted'. In this case,

CATSTRUCT(S1,S2, ..., 'sorted') will sort the fieldnames alphabetically. To sort the fieldnames of a structure A, you could use CATSTRUCT(A,'sorted') but I recommend ORDERFIELDS for doing that.

When there is nothing to concatenate, the result will be an empty struct (0x0 struct array with no fields).

NOTE

To concatenate similar arrays of structs, you can use simple concatenation:

A = dir('*.mat') ; B = dir('*.m') ; C = [A ; B] ;

Latest version: 4.0 (dec 2013)

Jos (10584) (2021). CATSTRUCT (https://www.mathworks.com/matlabcentral/fileexchange/7842-catstruct), MATLAB Central File Exchange. Retrieved .

Created with
R2014a

Compatible with any release

**Inspired:**
Lynx MATLAB Toolbox, Structable

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

Start Hunting!Create scripts with code, output, and formatted text in a single executable document.

Marius BrachvogelAlberto Gonzalez GarciaPing GaoLeopoldo BrasilMax BradburyVaibhav Pandeyshubhi bhadauriaccMangoWorks well for me.

Oleksii ZheloAlanJos (10584)@arnold Simply use any of the basic concatenation functions, for instance: z = cat(2, x.a, y.a]

If your structures are named like x1, x2, x3, you really need to reconsider your variable naming approach. You would be better off when you stored them in an array of structures:

z.a = cat(x(:).a)

arnoldI understand that it could lead to conflicts but do you have a better idea on how to append data to structures if the data format actually fits?

I have many usage scenarios where it would make sense to use structures for different variables with congruent data format but it then turns out to be quite cumbersome to simply consolidate them. Example: measurement-data

Jos (10584)@arnold, that behaviour would be quite arbitrary and depending on the contents of the field which may differ between the two structures. Example:

a.x = 'test', b.x = magic(3), catstruct(a,b) ??

arnoldany chance you can add the ability to append data if fieldnames already exist?

catstruct(a,a) then would result in a new struct with the same fields as a but double the entries in each field.

Gad MolkhoThanks a lot!

NugrahaThank you

RobertGreat function! Greetings from Croatia

David MERCIERDavid YoungAnton SemechkoSolenostomusGreat function, but not versatile enough for what I wanted. I also use structs for configuration settings, but my structs are nested (structs of structs of structs of values).

So I needed to add some recursion:

...

[UFN2,ind2] = unique(FN, 'last') ;

[UFN1,ind1] = unique(FN, 'first') ;

if numel(UFN2) ~= numel(FN),

%warning('catstruct:DuplicatesFound','Fieldnames are not unique between structures.') ;

sorted = 1 ;

end

if sorted,

VAL2 = cell(numel(ind2),1);

for n=1:numel(ind1)

v1 = VAL(ind1(n),:);

v2 = VAL(ind2(n),:);

if iscell(v1) && numel(v1)==1 && isstruct(v1{1}) && iscell(v2) && numel(v2)==1 && isstruct(v2{1})

v = cell(1,1); v{1} = catstruct(v1{1}, v2{1});

VAL2(n) = v;

else

VAL2(n) = v2;

end

end

FN = FN(ind2,:) ;

else

VAL2 = VAL;

end

A = cell2struct(VAL2, FN);

...

This edit only works when 2 structs are combined, which is fine for me (the default config struct and the user defined one), but it's not general because the calls to unique() only identify the first and last occurrence.

This would need more work for the general case and I may have broken some other use cases.

Brad StiritzGreat utility, thanks for providing this. Please be aware that your current version 4.0 generates two warnings in R2014b that nargchk() will be removed in a future MATLAB version.

ChristianSamColinKrzysztofnarginchk(1,Inf)

N = nargin ;

sorted = varargin { end };

if ischar(sorted)

narginchk(2,Inf)

assert (all (sorted == 'sorted'))

sorted = 1 ;

N = N-1 ;

else

sorted = 0 ;

end

Jos (10584)Thanks Christophe for pointing out the changed behavior of unique! I will fix this soon.

ChristopheOne solution to restore compatibility across MATLAB version would be to substitute line 124:

[UFN,ind] = unique(FN) ;

by

if verLessThan('matlab','8.1')

[UFN,ind] = unique(FN) ;

else

[UFN,ind] = unique(FN,'legacy') ;

end

ChristopheThis is a very useful function!

Unfortunately, it seems that the release of MATLAB 2013a breaks its behavior. They have changed the behavior of the function unique and now when I type

catstruct(struct('A',1),struct('A',2))

I get

A: 1

ChristopheJos (10584)@Tor Inge Birkenes

I see your problem! An update is being submitted ...

Tor Inge BL@Jos

If its inteded it is of course all right, but it feels inconsistent to me.

I care about this because I am using structs to store configuration parameters and use your function to merge standard and user defined values. In this case it is expected to have duplicate fields. As you point out this is outside the intended use of the function, but it still works great.

In case my explanation of the problem was insufficient i include concrete example this time:

% Defining struct arrays

s1.name = 'fred';

s1.age = 42;

s1(2).name = 'alice';

s1(2).age = 29;

s2.height = 170;

s2(2).height = 160;

% Concentrate

A=catstruct(s1,s2)

% A is a 1x2 struct array

% with fields: name, age, height

% Add duplicate field

s1(1).height= '142';

s1(2).height = '195';

% Concentrate

A2=catstruct(s1,s2)

% A2 is a struct with fields:

% name, age, height

I is the dimension difference (1x2 vs 1x1) that i find inconsistent, and I did not expect based on the warning "Warning: Duplicate fieldnames found. Last value is used and fields are sorted". I would expect an 1x2 array where the field values from s2 were used when there are conflict, as the function does with the first field in the structure.

Jos (10584)@Tor Inge Birkenes

This behaviour is intended. CATSTRUCT merges separate structures containing different(!) field names into 1. For instance, it works perfectly for the initial example given in Loren's blog.

Tor Inge BLGreat function!

I found a bug when concentrating struct arrays with common fields.

Then only the first struct was concentrated, the rest was discarded.

For an example add height-field to s1 in the example here, and concentrate: http://blogs.mathworks.com/loren/2009/10/15/concatenating-structs/#11

I fixed it by changing

VAL = VAL(ind) ;

FN = FN(ind) ;

to

VAL = VAL(ind,:,:) ;

FN = FN(ind,:,:) ;

at line 88-89. Seems to work nicely.

Winterspritesimple to use, but what I really wanted to do was to gather up 5 structures and put them into one structure variable, whereas this script flattened my existing structures.

WouterI also needed to concatenate arrays and cells at the leaf nodes in the case when the fieldnames match. This can be done by slightly adjusting the code as:

if numel(UFN) ~= numel(FN),

warning('catstruct:DuplicatesFound','Duplicate fieldnames found. Fields are merged and sorted.') ;

Nd = numel(unique(j));

for i=1:Nd

idx = find(j==unique(j(i)));

[nr,nc] = cellfun(@size, VAL(idx));

% comment if fields are not required to be equal in size:

if diff(nr) || diff(nc);error(['Duplicate field ' FN{idx(1)} ' does not have the same size for all structures.']);end

[p,rcm] = min([nc(1) nr(1) 2]);

% concatenate rows as rows, colums as colomns and matrices along 2nd dimension.

VAL{idx(end)} = cat(min(rcm,2),VAL{idx});

end

sorted = 1;

end

WoutergregaK EShould be standard in Matlab

Scott OttersonThis works well. I agree with Jeremy that recursive concatenation would be an advantage. It would also be useful to concatenate arrays and cells at the leaf nodes in the case when the fieldnames match (I've had to do this many times).

But it works for what I'm doing at the moment. Thanks!

Gabriel Akira Schreibergreat work, may the sun always shine on you.

JeremyNice work, just one comment:

I just noticed that when merging two structures, the fact that any dissimilar fields in the FIRST level are merged, but dissimilarities in subsequent levels are lost: e.g.

s1.a = 1;

s1.b = 2;

s2.a = 101;

s3 = catstruct(s1,s2) gives s3.a = 101, s3.b = 2.

But

s1.A.a = 1;

s1.A.b = 2;

s2.A.a = 101;

gives s3.A = a : 101.

i.e. we lose field b. I kind of understand the logic, i.e. that it is now field A that is being overwritten by a new field A, so that a depth=1 merge has occurred, but for anyone looking to do a true merge-style operation, this means needing to loop though each level... any plans to change this?

DanielJos (the author)To Benny. Catstruct does work on structures with non-numeric fields (see the example). You're after simple concatenation, for which you do not need catstruct at all ...

a = dir('*.mat')

b = dir('*.txt')

c = [a ; b] ;

Benny .Good job. It would be very usefull if it also worked on general structures, not only those containing numerical matrices only, e.g.

a = dir('*.txt');

b = dir('*.mat');

c = catstruct(a,b);

Piotr .Very useful function!

Maziar Hashemi-NezhadPerfect basic program

Thanks

Hoi WongCool program. I can't imagine why MATLAB wouldn't have something like this built-in, but you filled the gap!

Jos (the author)new version 2.0 (sep 2007). A bug was removed which ocured when fields contained cell arrays.

Jingzhao OuA very useful script!

Nadaraja PillaiHi ,

It is possible to concates the structure simply using collon... For example...

X=[S1:S2:S3....]

It will do it...

Paolo de LevaThis function is a must for people using structures. I wonder why MATLAB doesn't allow (as far as I know) structure concatenation using the [S1, S2] syntax, when the two structures have different fields. The builtin function STRUCT can't add fields to an existing structure...