%------------------------------------------------------------------------------
% 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.
%------------------------------------------------------------------------------