function A = catstruct(varargin) % 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] ; % % See also CAT, STRUCT, FIELDNAMES, STRUCT2CELL, ORDERFIELDS % for Matlab R13 and up % version 3.0 (mar 2013) % Originally downloaded from MATLAB central: % http://www.mathworks.com/matlabcentral/fileexchange/7842-catstruct % Copyright (C) 2005 Jos van der Geest % Copyright (C) 2013 Christophe Gouel % Copyright (C) 2016-2021 Dynare Team % % Redistribution and use in source and binary forms, with or without % modification, are permitted provided that the following conditions are % met: % % * Redistributions of source code must retain the above copyright % notice, this list of conditions and the following disclaimer. % * Redistributions in binary form must reproduce the above copyright % notice, this list of conditions and the following disclaimer in % the documentation and/or other materials provided with the distribution % % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE % POSSIBILITY OF SUCH DAMAGE. % History % Created in 2005 % Revisions % 2.0 (sep 2007) removed bug when dealing with fields containing cell % arrays (Thanks to Rene Willemink) % 2.1 (sep 2008) added warning and error identifiers % 2.2 (oct 2008) fixed error when dealing with empty structs (Thanks to % Lars Barring) % 3.0 (mar 2013) fixed problem when the inputs were array of structures % (thanks to Tor Inge Birkenes for pointing this out). % Rephrased the help section as well. narginchk(1, Inf); N = nargin ; if ~isstruct(varargin{end}) if isequal(varargin{end},'sorted') sorted = 1 ; N = N-1 ; if N<1 error('catstruct: wrong number of input arguments') ; end else error('catstruct:InvalidArgument','Last argument should be a structure, or the string "sorted".') ; end else sorted = 0 ; end sz0 = [] ; % used to check that all inputs have the same size % used to check for a few trivial cases NonEmptyInputs = false(N,1) ; NonEmptyInputsN = 0 ; % used to collect the fieldnames and the inputs FN = cell(N,1) ; VAL = cell(N,1) ; % parse the inputs for ii=1:N X = varargin{ii} ; if ~isstruct(X) error('catstruct:InvalidArgument',['Argument #' num2str(ii) ' is not a structure.']) ; end if ~isempty(X) % empty structs are ignored if ii > 1 && ~isempty(sz0) if ~isequal(size(X), sz0) error('catstruct:UnequalSizes','All structures should have the same size.') ; end else sz0 = size(X) ; end NonEmptyInputsN = NonEmptyInputsN + 1 ; NonEmptyInputs(ii) = true ; FN{ii} = fieldnames(X) ; VAL{ii} = struct2cell(X) ; end end if NonEmptyInputsN == 0 % all structures were empty A = struct([]) ; elseif NonEmptyInputsN == 1 % there was only one non-empty structure A = varargin{NonEmptyInputs} ; if sorted A = orderfields(A) ; end else % there is actually something to concatenate FN = cat(1,FN{:}) ; VAL = cat(1,VAL{:}) ; FN = squeeze(FN) ; VAL = squeeze(VAL) ; MatlabVersion = version; [UFN,ind] = unique(FN,'legacy') ; if numel(UFN) ~= numel(FN) warning('catstruct:DuplicatesFound','Fieldnames are not unique between structures.') ; sorted = 1 ; end if sorted VAL = VAL(ind,:) ; FN = FN(ind,:) ; end A = cell2struct(VAL, FN); A = reshape(A, sz0) ; % reshape into original format end