Home > marsbar > mars_struct.m

mars_struct

PURPOSE ^

multifunction function for manipulating structures

SYNOPSIS ^

function varargout = mars_struct(action, varargin)

DESCRIPTION ^

 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$

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

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

Generated on Wed 11-May-2022 16:26:09 by m2html © 2003-2019