Home > atmlab > handy > catstruct.m

catstruct

PURPOSE ^

CATSTRUCT - concatenate structures

SYNOPSIS ^

function A = catstruct(varargin)

DESCRIPTION ^

 CATSTRUCT - concatenate structures

   X = CATSTRUCT(S1,S2,S3,...) concates the structures S1, S2, ... into one
   structure X. 

   Example:
     A.name = 'Me' ; 
     B.income = 99999 ; 
     X = catstruct(A,B) 
     % -> X.name = 'Me' ;
     %    X.income = 99999 ;

   CATSTRUCT(S1,S2,'sorted') will sort the fieldnames alphabetically.

   If a fieldname occurs more than once in the argument list, only the last
   occurence is used, and the fields are alphabetically sorted.

   To sort the fieldnames of a structure A use:
     A = CATSTRUCT(A,'sorted') ;

   To concatenate two similar array of structs use simple concatenation:
     A = dir('*.mat') ; B = dir('*.m') ; C = [A ; B] ;

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

   See also CAT, STRUCT, FIELDNAMES, STRUCT2CELL

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

DOWNLOAD ^

catstruct.m

SOURCE CODE ^

0001 function A = catstruct(varargin)
0002 % CATSTRUCT - concatenate structures
0003 %
0004 %   X = CATSTRUCT(S1,S2,S3,...) concates the structures S1, S2, ... into one
0005 %   structure X.
0006 %
0007 %   Example:
0008 %     A.name = 'Me' ;
0009 %     B.income = 99999 ;
0010 %     X = catstruct(A,B)
0011 %     % -> X.name = 'Me' ;
0012 %     %    X.income = 99999 ;
0013 %
0014 %   CATSTRUCT(S1,S2,'sorted') will sort the fieldnames alphabetically.
0015 %
0016 %   If a fieldname occurs more than once in the argument list, only the last
0017 %   occurence is used, and the fields are alphabetically sorted.
0018 %
0019 %   To sort the fieldnames of a structure A use:
0020 %     A = CATSTRUCT(A,'sorted') ;
0021 %
0022 %   To concatenate two similar array of structs use simple concatenation:
0023 %     A = dir('*.mat') ; B = dir('*.m') ; C = [A ; B] ;
0024 %
0025 %   When there is nothing to concatenate, the result will be an empty
0026 %   struct (0x0 struct array with no fields).
0027 %
0028 %   See also CAT, STRUCT, FIELDNAMES, STRUCT2CELL
0029 
0030 % for Matlab R13 and up
0031 % version 2.2 (oct 2008)
0032 % (c) Jos van der Geest
0033 % email: jos@jasen.nl
0034 % Copyright (c) 2009, Jos van der Geest
0035 % All rights reserved.
0036 
0037 % History
0038 % Created:  2005
0039 % Revisions
0040 %   2.0 (sep 2007) removed bug when dealing with fields containing cell
0041 %                  arrays (Thanks to Rene Willemink)
0042 %   2.1 (sep 2008) added warning and error identifiers
0043 %   2.2 (oct 2008) fixed error when dealing with empty structs (Thanks to
0044 %                  Lars Barring)
0045 % Modified by Salomon Eliassson. 2011
0046 %       additions: Works recursively
0047 %                  Allows empty arguments in varargin
0048 % $Id: catstruct.m 8495 2013-06-18 08:20:05Z seliasson $
0049 
0050 N = nargin ;
0051 
0052 narginchk(1,Inf) ;
0053 
0054 if ~isstruct(varargin{end}),
0055     if isequal(varargin{end},'sorted'),
0056         sorted = 1 ;
0057         N = N-1 ;
0058         if N < 1,
0059             A = struct([]) ;
0060             return
0061         end
0062     else
0063         error(['atmlab:' mfilename, ':badInput'],...
0064             'Last argument should be a structure, or the string "sorted".') ;
0065     end
0066 else
0067     sorted = 0 ;
0068 end
0069 
0070 FN = cell(N,1) ;
0071 VAL = cell(N,1) ;
0072 
0073 for ii=1:N,
0074     X = varargin{ii} ;
0075     if ~isempty(X) % Added by Salomon (allow empty arguments)
0076         if ~isstruct(X),
0077             error('catstruct:InvalidArgument',...
0078                 ['Argument #' num2str(ii) ' is not a structure.']) ;
0079         end
0080         % empty structs are ignored
0081         FN{ii} = fieldnames(X) ;
0082         VAL{ii} = struct2cell(X) ;
0083     end
0084 end
0085 
0086 % Added by Salomon --
0087 FN = FN(~cellfun('isempty',FN));
0088 VAL = VAL(~cellfun('isempty',VAL));
0089 
0090 [FN,VAL] = recursive_catstruct(FN,VAL);
0091 % --
0092 
0093 FN = cat(1,FN{:}) ;
0094 VAL = cat(1,VAL{:}) ;
0095 [UFN,ind] = unique(FN) ;
0096 
0097 if numel(UFN) ~= numel(FN),
0098     warning('catstruct:DuplicatesFound',...
0099         'Duplicate fieldnames found. Last value is used and fields are sorted') ;
0100     sorted = 1 ;
0101 end
0102 
0103 if sorted,
0104     VAL = VAL(ind) ;
0105     FN = FN(ind) ;
0106 end
0107 
0108 if ~isempty(FN),
0109     % This deals correctly with cell arrays
0110     A = cell2struct(VAL, FN, 1);
0111 else
0112     A = struct([]) ;
0113 end
0114 
0115 %%%%%%%%%%%%%%%
0116 % SUBFUNCTIONS
0117 %
0118 function [FN,VAL] = recursive_catstruct(FN,VAL)
0119 %% recursive_catstruct
0120 
0121 % Look for structures in structure...
0122 a = cell(size(FN,1),1);
0123 for i =1:size(FN,1)
0124     % find which structures contain structures
0125     a{i}= FN{i}(cellfun(@isstruct,VAL{i}));
0126 end
0127 
0128 if all(cellfun('isempty',a))
0129     return
0130 end
0131 
0132 % get the unique structure names
0133 F = unique(cat(1,a{:}));
0134 
0135 for f = F'
0136     % find the lower level structure in the the other structures
0137     structs_index = cell2mat(cellfun(@(X)any(ismember(X,f)),a,'uniformoutput',0));
0138     
0139     if sum(structs_index)==1 % don't need to do more
0140         continue
0141     end 
0142     
0143     %logtext(atmlab('OUT'), 'Stucture element: ''%s'' will be dealt with recursively\n',f{1})
0144     % If this low level structure appears in more than 1 main level structure,
0145     % do another catstruct
0146     
0147     fnd = 1:length(structs_index);
0148     vargin = cell(sum(structs_index),1);
0149     for loop = fnd(structs_index)
0150         vargin{loop} = VAL{loop}{ismember(FN{loop},f)}; % this is the low level struct
0151     end
0152     merged_lowstruct.(f{1}) = catstruct(vargin{:});
0153 end
0154 if ~exist('merged_lowstruct','var'), return, end % nothing was done
0155 
0156 % Just make a extra structure knowing that this will be appended last and will
0157 % overwrite the others with the conflicting fields structure elements that are
0158 % also structures
0159 lowlvlF = fieldnames(merged_lowstruct);
0160 for lF = lowlvlF'
0161     FN{end+1} = lF{1}; %#ok<AGROW>
0162     VAL{end+1} = merged_lowstruct.(lF{1}); %#ok<AGROW>
0163 end

Generated on Mon 15-Sep-2014 13:31:28 by m2html © 2005