multifunction function for manipulating structures To help the exposition a bit: 'fill' in a name, means that values empty or missing in one structure are fetched from another 'merge' means simply that missing fields are added, with values, from a second structure (but not filled if empty) Each function needs to deal with the case of empty arguments FORMAT c = mars_struct('fillafromb', a, b, fieldns, flags) fills structure fields empty or missing in a from those present in b a, b are structures fieldns (optional) is cell array of field names to fill from in b c is returned structure Is recursive, will fill struct fields from struct fields flags may contain 'f', which Force fills a from b (all non empty fields in b overwrite those in a) flags may also contain 'r', which Restricts fields to write from b, to those that are already present in a FORMAT [c, d] = mars_struct('split', a, b) split structure a into two, according to fields in b so that c becomes a structure which contains the fields in a, that are also present in b, and d contains the fields in a that are not present in b. b can be a structure or a cell array of fieldnames FORMAT [d] = mars_struct('strip', a, b) strips all fields present in b from those in a, returning denuded structure as d. b can be a structure or a cell array of fieldnames. 'strip' is just 'split' but returning only the second argument FORMAT c = mars_struct('merge', a, b) merges structure a and b (fields present in b added to a) FORMAT [c,d] = mars_struct('ffillsplit', a, b) force fill, followed by split All fields from a, that are also present in b, and not empty in b, are replaced with the values in b; the result is returned as c Any fields present in b, but not present in a, are returned in d So, let's say you have a default structure D, and you want to fill this in with any interesting data in a passed structure P, you could use: [good_struct not_recognized]= mars_struct('ffillsplit', D, P); FORMAT c = mars_struct('ffillmerge', a, b) force fill followed by merge performs 'ffillsplit' on a and b, then merges a and b All fields present in a or b are returned in c, but any fields present in both, now have the value from b FORMAT [c d] = mars_struct('splitmerge', a, b) performs 'split' on a and b, creating c and d then merges c with b. d contains fields in a that were not present in b c contains fields present in both, or just in b FORMAT z = mars_struct('isthere', a, b [, c [, d ...]) returns 1 if field named in b is present in a and field value is not empty. The call is recursive if more than two arguments are passed Thus with structure s = struct('one', struct('two', 3)) mars_struct('isthere', s, 'one', 'two') returns 1 FORMAT z = mars_struct('getifthere', a, b [, c [, d ...]) returns value of field named in b from a or [] if absent Call is recursive, like 'isthere' above. FORMAT strs = mars_struct('celldisp', a) returns output like disp(a) as a cell array Useful for printing text description of structure $Id$
0001 function varargout = mars_struct(action, varargin) 0002 % multifunction function for manipulating structures 0003 % 0004 % To help the exposition a bit: 0005 % 'fill' in a name, means that values empty or missing 0006 % in one structure are fetched from another 0007 % 0008 % 'merge' means simply that missing fields are added, with 0009 % values, from a second structure (but not filled if empty) 0010 % 0011 % Each function needs to deal with the case of empty arguments 0012 % 0013 % FORMAT c = mars_struct('fillafromb', a, b, fieldns, flags) 0014 % fills structure fields empty or missing in a from those present in b 0015 % a, b are structures 0016 % fieldns (optional) is cell array of field names to fill from in b 0017 % c is returned structure 0018 % Is recursive, will fill struct fields from struct fields 0019 % flags may contain 'f', which Force fills a from b (all non empty 0020 % fields in b overwrite those in a) 0021 % flags may also contain 'r', which Restricts fields to write from b, to 0022 % those that are already present in a 0023 % 0024 % FORMAT [c, d] = mars_struct('split', a, b) 0025 % split structure a into two, according to fields in b 0026 % so that c becomes a structure which contains the fields 0027 % in a, that are also present in b, and d contains the fields 0028 % in a that are not present in b. b can be a structure 0029 % or a cell array of fieldnames 0030 % 0031 % FORMAT [d] = mars_struct('strip', a, b) 0032 % strips all fields present in b from those in a, 0033 % returning denuded structure as d. b can be a structure 0034 % or a cell array of fieldnames. 'strip' is just 'split' 0035 % but returning only the second argument 0036 % 0037 % FORMAT c = mars_struct('merge', a, b) 0038 % merges structure a and b (fields present in b added to a) 0039 % 0040 % FORMAT [c,d] = mars_struct('ffillsplit', a, b) 0041 % force fill, followed by split 0042 % All fields from a, that are also present in b, and not empty in b, 0043 % are replaced with the values in b; the result is returned as c 0044 % Any fields present in b, but not present in a, are returned in d 0045 % So, let's say you have a default structure D, and you want to fill this 0046 % in with any interesting data in a passed structure P, you could use: 0047 % [good_struct not_recognized]= mars_struct('ffillsplit', D, P); 0048 % 0049 % FORMAT c = mars_struct('ffillmerge', a, b) 0050 % force fill followed by merge 0051 % performs 'ffillsplit' on a and b, then merges a and b 0052 % All fields present in a or b are returned in c, but 0053 % any fields present in both, now have the value from b 0054 % 0055 % FORMAT [c d] = mars_struct('splitmerge', a, b) 0056 % performs 'split' on a and b, creating c and d 0057 % then merges c with b. 0058 % d contains fields in a that were not present in b 0059 % c contains fields present in both, or just in b 0060 % 0061 % FORMAT z = mars_struct('isthere', a, b [, c [, d ...]) 0062 % returns 1 if field named in b is present in a 0063 % and field value is not empty. 0064 % The call is recursive if more than two arguments are passed 0065 % Thus with structure s = struct('one', struct('two', 3)) 0066 % mars_struct('isthere', s, 'one', 'two') returns 1 0067 % 0068 % FORMAT z = mars_struct('getifthere', a, b [, c [, d ...]) 0069 % returns value of field named in b from a or [] if absent 0070 % Call is recursive, like 'isthere' above. 0071 % 0072 % FORMAT strs = mars_struct('celldisp', a) 0073 % returns output like disp(a) as a cell array 0074 % Useful for printing text description of structure 0075 % 0076 % $Id$ 0077 0078 if nargin < 1 0079 error('Action needed'); 0080 end 0081 if nargin < 2 0082 error('Must specify structure') 0083 end 0084 if nargin < 3 0085 varargin = {varargin{:} []}; 0086 end 0087 [a b] = deal(varargin{1:2}); 0088 0089 switch lower(action) 0090 case 'fillafromb' 0091 % Return for empty passed args 0092 if isempty(a), varargout = {b}; return, end 0093 if isempty(b), varargout = {a}; return, end 0094 if nargin < 4, fieldns = []; else fieldns = varargin{3}; end 0095 if isempty(fieldns) 0096 if ~isstruct(b), error('Need struct as 2nd argument'); end 0097 fieldns = fieldnames(b); 0098 end 0099 if nargin < 5, flags = ''; else flags = varargin{4}; end 0100 if isempty(flags), flags = ' ';end 0101 0102 if ischar(fieldns), fieldns=cellstr(fieldns);end 0103 0104 af = fieldnames(a)'; 0105 bf = fieldns'; 0106 0107 % classify fields 0 = a~b, 1 = a&b, 2=b~a 0108 cf = af; 0109 ftype = ismember(af, bf); 0110 if ~any(flags == 'r') 0111 b_not_a = find(~ismember(bf, af)); 0112 cf = {cf{:} bf{b_not_a}}; 0113 ftype = [ftype ones(1, length(b_not_a))*2]; 0114 end 0115 0116 % cope with arrays of structures 0117 alen = prod(size(a)); 0118 blen = prod(size(b)); 0119 maxlen = max(alen, blen); 0120 0121 for si=1:maxlen 0122 ctmp = []; 0123 for i=1:length(cf) 0124 fn = cf{i}; 0125 switch ftype(i) 0126 case 0 % a~b 0127 fval = getfield(a(si), fn); 0128 case 1 % shared field 0129 bfc = getfield(b(si), fn); 0130 if isempty(getfield(a(si), fn)) || ... % a field is empty 0131 (any(flags == 'f' && ~isempty(bfc)))% or force fill 0132 fval = bfc; 0133 else % field not empty, could be struct -> recurse 0134 fval = getfield(a(si),fn); 0135 if isstruct(fval) && isstruct(bfc) 0136 fval = mars_struct('fillafromb',fval,bfc); 0137 end 0138 end 0139 case 2 % b~a 0140 fval = getfield(b(si), fn); 0141 case 3 % no field information, see below 0142 fval = []; 0143 end 0144 if isempty(ctmp) 0145 ctmp = struct(fn, fval); 0146 else 0147 ctmp = setfield(ctmp, fn, fval); 0148 end 0149 end 0150 c(si) = ctmp; 0151 0152 if si == blen % reached end of bs, rest of b~a fields are empty 0153 ftype = (ftype == 2) * 3; 0154 elseif si == alen % end of a's rest of a~b fields are empty 0155 ftype = (ftype == 0) * 2 + 1; 0156 end 0157 0158 end 0159 varargout = {c}; 0160 0161 case 'split' 0162 if isempty(a), varargout = {a,a}; return, end 0163 if isempty(b), varargout = {b,a}; return, end 0164 d = a; 0165 c = []; 0166 0167 if ischar(b), b = {b};end 0168 if isstruct(b), b = fieldnames(b);end 0169 0170 for bf = b(:)' 0171 if isfield(a, bf{1}) 0172 c = setfield(c, bf{1}, getfield(a, bf{1})); 0173 d = rmfield(d, bf{1}); 0174 end 0175 end 0176 varargout = {c, d}; 0177 0178 case 'strip' 0179 [c d] = mars_struct('split', a, b); 0180 varargout = {d}; 0181 0182 case 'merge' 0183 if isempty(a), varargout = {b}; return, end 0184 if isempty(b), varargout = {a}; return, end 0185 c = a; 0186 0187 for bf = fieldnames(b)'; 0188 if ~isfield(a, bf{1}) 0189 c = setfield(c, bf{1}, getfield(b, bf{1})); 0190 end 0191 end 0192 varargout = {c}; 0193 0194 case 'ffillsplit' 0195 if isempty(a) || isempty(b) 0196 % Nothing in common, return unchanged 0197 varargout = {a, b}; return 0198 end 0199 c = a; d = b; 0200 0201 cf = fieldnames(c); 0202 for i=1:length(cf) 0203 if isfield(d, cf{i}) 0204 dfc = getfield(d,cf{i}); 0205 if ~isempty(dfc) 0206 c = setfield(c, cf{i}, dfc); 0207 end 0208 d = rmfield(d, cf{i}); 0209 end 0210 end 0211 varargout = {c,d}; 0212 0213 case 'ffillmerge' 0214 [a b] = mars_struct('ffillsplit', a, b); 0215 varargout = {mars_struct('merge', a, b)}; 0216 0217 case 'splitmerge' 0218 [a c] = mars_struct('split', a, b); 0219 varargout = {mars_struct('merge', a, b) c}; 0220 0221 case 'isthere' 0222 if isempty(a), varargout = {0}; return, end 0223 c = mars_struct('getifthere', varargin{:}); 0224 varargout = {~isempty(c)}; 0225 0226 case 'getifthere' 0227 if isempty(a), varargout = {[]}; return, end 0228 if isempty(b), varargout = {[]}; return, end 0229 for v = 2:nargin-1 0230 b = varargin{v}; 0231 if ~isfield(a, b) 0232 varargout = {[]}; 0233 return 0234 end 0235 a = getfield(a, b); 0236 end 0237 varargout = {a}; 0238 0239 case 'celldisp' 0240 if isempty(a), varargout = {{}}; return, end 0241 af = fieldnames(a); 0242 c = {}; 0243 pad_len = size(char(af), 2) + 4; 0244 pad_str = ['%' num2str(pad_len) 's: %s']; 0245 for f = 1:length(af) 0246 d = getfield(a, af{f}); 0247 cls = class(d); 0248 sz = size(d); 0249 szstr = sprintf('%dx', size(d)); 0250 szstr(end) = []; 0251 switch cls 0252 case 'char' 0253 case {'double', 'float'} 0254 d = ['[' num2str(d) ']']; 0255 otherwise 0256 d = sprintf('[%s %s]', szstr, cls); 0257 end 0258 c{f} = sprintf(pad_str, af{f}, d); 0259 end 0260 varargout = {c}; 0261 0262 otherwise 0263 error(['Suspicious action was ' action]); 0264 end % switch