%------------------------------------------------------------------------------
% Advanced MATLAB

% + want to model multiple and related info
% + Tedious way: use many variables

% ex) model people
      fn1 = 'gene';
      ln1 = 'demaitre';
      id1 = 1234;

      fn2 = 'ben';
      ln2 = 'stein';
      id2 = 4321;

      % assume even more people!
    
% + Notes:
%   - different types causes weird behavior:
%     A = [1 'aa'] 
%     outputs just $aa$ (weird)
%   - even if use all strings, strings diff lengths (each char = 1 col)
%     A = ['a' 'bb' ; 'ccc' 'd']
%     causes error message because row 1 needs 3 cols and row 2 needs 4 cols

% + Want to:
%   - reduce redundant code
%   - clearly model "multiple" constructs (many parts make whole)

% + But how? use
%   - cell arrays
%   - structure arrays
% + exploring these leads into OOP!
%------------------------------------------------------------------------------
% CELL ARRAYS (CAs)
% =================
% General:
% + most "general" MATLAB data structure
% + special kind of array
% + holds arrays (including CAs) inside elements   
% + arrays may be different types!
% + no math operations allowed (ML would get too confused)
% + cells called CONTAINERS
%------------------------------------------------------------------------------
% Creating CAs:
% + Preallocation with $cell$
% + using {} notation
%------------------------------------------------------------------------------
% Creating CA: Preallocation:
  help cell

% Portion of help file:
% CELL  Create cell array.
%    CELL(N) is an N-by-N cell array of empty matrices. 
%    CELL(M,N) or CELL([M,N]) is an M-by-N cell array of empty
%    matrices.

% ex) create an empty 2x2 cell array
      cell(2)
%     gives 4 empty matrices:
%     ans = 
%
%          []     []
%          []     []
%------------------------------------------------------------------------------
% Creating CA: Using {} notation
% + three ways:
%   - using {} directly:  {row stuff ; more row stuff ; etc }
%   - cell indexing:      array(indicies) = {stuff}
%   - content indexing:   array{indicies} = stuff
% + all methods identical for results!

%   Direct
%   ======
    A = {'ben' 'stein' ; 4321 [] }
%   A = 
%
%      'ben'     'stein'
%       [4321]         []

%   Cell indexing
%   =============
    A(1,1) = {'ben'}; 
    A(1,2) = {'stein'};
    A(2,1) = {4321};
    A(2,2) = {[]};
    A
%   A = 
%
%      'ben'     'stein'
%       [4321]         []

%   Content indexing
%   ================
    A{1,1} = 'ben'; 
    A{1,2} = 'stein';
    A{2,1} = 4321;
    A{2,2} = [];
    A
%   A = 
%
%      'ben'     'stein'
%       [4321]         []

% See? Same results
% Related ops:
% - extending cell arrays: see Chapman p264 (ex: B=A; B{3,3} = 'hello')
% - deleting elements: see Chapman 266 (ex: B(1,:) = [] deletes 1st row)
% - reshape: see $help reshape$ (ex: reshape(A,1,4))
% - combining: ex) C = [A A] creates a new cell array with twice A
%------------------------------------------------------------------------------
% CA: Displaying all contents
% + entering variable (see above examples)
    A

% + $celldisp$
    celldisp(A)            
%   A{1,1} =
%            ben
%   A{2,1} =
%            4321
%   A{1,2} =
%            stein
%   A{2,2} = 
%            []

% + $cellplot$
%   boxes indicate the number of items in each cell
    cellplot(A)
%------------------------------------------------------------------------------
% CA: Displaying some contents

% () -> refers to contents that a cell points to
%    -> () index the cells directly
% {} -> refers to the actual contents pointed to by a cell
%    -> {} retrieve the data directly

  ex) B={'ira!' [1 2;3 4])

  B(2) % gives $[2x2 double]$
       % $B(2)$ is really a POINTER to a data structure
       % The pointer is an address that gives the location in computer memory 
       % for the contents referred to by the cell.

  B(1), B(2)  % could also just enter $B$

% ans = 
%    'ira'
% ans = 
%    [2x2 double]

  B{2} % gives [1 2;3 4]
       % $B(2)$ extracts the CONTENTS of the data structure
       % referred to by $B(2)$

  B{1}, B{2}

% ans =
%     'ira'
% ans =
%     1     2
%     3     4

% Notes:
% - individual values and strings are extracted in both cases
%   (because they are scalars)
% - extract individual elements of a structure inside a cell
%   ex) B{2}(1:4)
%       ans = 1 3 2 4
%       (pretty cool, huh?)
%------------------------------------------------------------------------------
% Application of CA: cell array of strings
% + strings are arrays of characters
% + storing unequal length strings in array sickens ML
% + you could pad strings with blanks, but...
% + Cell arrays to the rescue!

  S{1} = 'I';
  S{2} = 'love';
  S{3} = 'MATLAB!';
  S
% S = 
%    'I'    'love'    'MATLAB!'

% Shortcuts:
% + $help cellstr$
% + S = {'I'    'love'    'MATLAB!};

% Related functions:
% $iscellstr$, $ischar$
%------------------------------------------------------------------------------
% STRUCTURE ARRAYS (SAs)
% ======================
% General:
% + special kind of array
% + holds arrays inside elements   
% + arrays may be different types!
% + addresses elements by names called FIELDS
%   (CAs address elements by numerical indicies)
% + SAs usually 1-D but can be multi-dim
%------------------------------------------------------------------------------
% Creating SAs
% ============
% + Just make assignments
% + to store values use the $.$ operator
%   syntax: name.field=value

  A.fn = 'ben'; 
  A.ln = 'stein';
  A.id = 4321
  pause
% A = 
%    fn: 'ben'
%    ln: 'stein'
%    id: 4321
%
% Note:
% + ML will display a reference if the field is not 1-D
% + Try $A.x = [1:3;3:5]$ and then displaying $A$
    A.x = [1:3;3:5]
    pause
%------------------------------------------------------------------------------
% Retrieve values
  A.fn
% ans =
% ben
%------------------------------------------------------------------------------
% Fields can be any other data structure, including another SA

% Create a new SA
  B.tests = [99 88]
  B.projects = [10 10 10];
  B
  pause
% B = 
%       tests: [99 88]
%    projects: [10 10 10]

% Create new field of A called $scores$
% Assign scores in $B$ to $A$
  A.scores = B
% A = 
%        fn: 'ben'
%        ln: 'stein'
%        id: 4321
%         x: [2x3 double] % for 9:05am, this is supposed to be 2x3, not 2x2
%    scores: [1x1 struct] % this is indeed correct!
%
% Notes:
% + $scores$ and $x$ values NOT 1-D, so ML uses pointers
% + But, values are still there!
% + Access particular value
%   name.(substructure access) means name.name.field
    A.scores.tests
%   ans =
%   99    88
%------------------------------------------------------------------------------
% Additional Things:
% help struct
% help rmfield
% help getfield
% help setfield

% Preallocation
  SA1 = struct('x',0,'y',1)
% SA1 = 
%
%    x: 0
%    y: 1

% Removing fields
% + ML's SAs have a feature not common to other languages
% + Entering $rmfield$ will remove the NAME and CONTENTS of a field
% A = rmfield(A,'x')
% pause
% A = 
%
%    fn: 'ben'
%    ln: 'stein'
%    id: 4321
%    scores: [1x1 struct]
%------------------------------------------------------------------------------
% Array of Structures
% + can create an array of SAs by "adding" another SA
%   - start with initial SA and make another
%   - give 1 or more fields a value
%   - ML automatically creates a new SA
%   - empty fields represented as empty array $[]$

  A(2).fn = 'gene';
  A(2)
% ans = 
%
%        fn: 'gene'
%        ln: []
%        id: []
%         x: []
%    scores: []

% + What's an array of SAs???
  A
% A = 
%
% 1x2 struct array with fields:
%    fn
%    ln
%    id
%    x
%    scores

% + to get individual SAs, enter $A(1),A(2)$
  pause
%------------------------------------------------------------------------------
% Cell Arrays and Structure Arrays
% + Store info with $struct$
    s = struct('colors',{'blue','red','yellow'})
%   s = 
%
%   1x3 struct array with fields:
%      colors

% + $struct2cell$ and $cell2struct$
% help cell2struct                               
% CELL2STRUCT Convert cell array to structure array.
%    S = CELL2STRUCT(C,FIELDS,DIM) converts the cell array C into
%    the structure S by folding the dimension DIM of C into fields of
%    S.  SIZE(C,DIM) must match the number of field names in FIELDS.
%    FIELDS can be a character array or a cell array of strings.
% Huh?
% -> the number of columns of C must match the number of elements of FIELDS
% -> FIELDS is going to be 1-D array

 CA = {'ben' 'stein' ; 4321 []};
 % use $reshape$ (takes elements from cols)
 SA = cell2struct(reshape(CA,1,4),{'fn','id','ln','blank'},2)

% SA = 
%       fn: 'ben'
%       id: 4321
%       ln: 'stein'
%    blank: []

% Get lost? Check type:
  class(SA) % struct
  class(CA) % cell
%------------------------------------------------------------------------------
% Do structure array fields know about changes to
% another structure array? No. See below:
  clear
  echo on
  clc

% Create an SA
  sa2.y=2;
  pause

% store $sa2$ as a field of $sa1$
  sa1.x=sa2;
  pause

% Check output
  sa1       %  x: [1x1 struct]
  sa1.x     %  y: 2
  sa1.x.y   %  2
  pause

% Now, change value inside $sa2$
  sa2.y=3;
  pause

% What happened to $sa1$ and $sa2$?
  sa2       % y: 3
  sa2.y     % 3
  pause     % 

  sa1       % x: [1x1 struct]
  sa1.x     % y: 2
  sa1.x.y   % 2

% Yes, the values inside x do NOT change.
% This behavior is different in Java, where the values change.

% $sa1.x$ still points to an array, but that array does not change
% when $sa2$ changes.
%------------------------------------------------------------------------------
