0% found this document useful (0 votes)
8 views

LectureNotes8-24

CENG 15 notes

Uploaded by

hannah banana
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

LectureNotes8-24

CENG 15 notes

Uploaded by

hannah banana
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 30

CHAPTER 8: Data Structures: Cell Arrays and Structures

Data structures are variables that store more than one value.

CELL ARRAYS

------------

One type of data structure, which MATLAB has but is not found in many

programming languages, is a cell array. A cell array in MATLAB is an array,

but, unlike the vectors and matrices we have used so far, elements in cell

arrays are cells that can store different types of values.

Creating Cell Arrays

In creating cell arrays, curly braces are used rather than square brackets

which we used for creating regular arrays:

>> cellrowvec = {23, 'a', 1:2:9, 'hello'} % comma can be ommited,

% like in any row array

cellrowvec =

1x4 cell array

{[23]} {'a'} {1x5 double} {'hello'}

To create a column vector cell array, the values are instead separated by

semicolons:

>> cellcolvec = {23; 'a'; 1:2:9; 'hello'}


cellcolvec =

4x1 cell array

{[ 23]}

{'a' }

{1x5 double}

{'hello' }

*************

You can also create a 2 x 2 cell array matrix:

>> cellmat = {23 'a'; 1:2:9 'hello'}

cellmat =

2x2 cell array

{[ 23]} {'a' }

{1x5 double} {'hello'}

The type of cell arrays is cell.

>> class(cellmat)

ans =

'cell'

It is much more efficient, if the size is known ahead of time,


to preallocate the array. For cell arrays, this is done with the cell

function. For example, to preallocate a variable mycellmat to be a

2 x 2 cell array, the cell function would be called as follows:

>> mycellmat = cell(2,2)

mycellmat =

2x2 cell array

{0x0 double} {0x0 double}

{0x0 double} {0x0 double}

******

Referring to and Displaying Cell Array Elements and Attributes

Using curly braces for the subscripts will reference the contents of a cell;

this is called content indexing:

cellrowvec = {23, 'a', 1:2:9, 'hello'};

> cellrowvec{2}

ans =

'a'

class(ans)

'char'

sum(cellrowvec{3})

ans =
25

******

Row and column subscripts are used to refer to the contents of an element in

a matrix (again using curly braces):

>> cellmat{1,1}

ans =

23

Using parentheses for the subscripts references the cells;

this is called cell indexing:

cellrowvec = {23, 'a', 1:2:9, 'hello'};

> cellrowvec(2)

ans=

{'a'}

class(ans)

'cell'

cellcolvec = {23; 'a'; 1:2:9; 'hello'}

>> cellcolvec(2)

ans =

{'a'}

class(ans)

ans =

cell
Notice in the following the difference between what is displayed

when cell indexing and when content indexing:

cellmat = {23 'a'; 1:2:9 'hello'}

cellmat =

2x2 cell array

{[ 23]} {'a' }

{1x5 double} {'hello'}

>> cellmat(2,1)

ans =

1x1 cell array

{1x5 double}

>> cellmat{2,1}

ans =

13579

As the last statement results in a vector, parentheses can be used to

refer to its elements:

>> cellmat{2,1}(4)

ans =
7

To delete an element from a vector cell array, use cell indexing:

cellrowvec = {23, 'a', 1:2:9, 'hello'};

>> cellrowvec

cellrowvec =

[23] 'a' [1x5 double] 'hello'

>> cellrowvec(2) = []

cellrowvec =

[23] [1x5 double] 'hello'

Please compare with

cellrowvec{2}=[]

{[23]} {0×0 double} {[1 3 5 7 9]} {'hello'}

******

Storing Strings in Cell Arrays

One useful application of a cell array is to store strings of different

lengths:

>> names = {'Sue', 'Cathy', 'Xavier'}

names =
1×3 cell array

'Sue' 'Cathy' 'Xavier'

This is extremely useful because, unlike vectors of strings created using

char, these strings do not have extra trailing blanks:

>> for i = 1:length(names)

disp(length(names{i}))

end

The char function can convert from a cell array to a character matrix:

>> names = {'Sue', 'Cathy', 'Xavier'};

>> cnames = char(names)

cnames =

3×6 char array

'Sue '

'Cathy '

'Xavier'

>> size(cnames)

ans =
36

The function iscellstr will return logical true if a cell array is a cell

array of all strings or logical false if not.

>> iscellstr(names)

ans =

>> iscellstr(cellcolvec)

ans =

%%%%

Subcells

cellarrsub ={

'exp', {0, 2, 0.01};

'log', {1, 2, 0.02};

'sin', {-pi/2, pi/2, pi/200};

'log10', {1, 3, 0.02}

};

****

class(cellarrsub)

ans =
'cell'

size(cellarrsub)

ans=

4 2

*******

cellarrsub{3,2};

ans =

1x3 cell array

{[-1.5708]} {[1.5708]} {[0.0157]}

******

cellarrsub{end,2}{3} %end is in this case = 4 (4th cell, third entry

% of second subcell = 0.02)

ans =

0.0200

******

x = cellarrsub{1,2}{1}: cellarrsub{1,2}{3}: cellarrsub{1,2}{2};

y = eval([cellarrsub{1,1} '(x)']);

plot(x,y)
*****************

Look also at this:

a = {'sin', [1, 2, 5], @sin}

a{1,2}(3)=5 % or a{1,2}(1,3)=5 %

% here: [1,2,5] is a single cell (integer array, not a cell array)

b = {'sin', {1, 2, 5}, @sin}

b{1,2}{3}=5 % because {1,2,5} is a cell array, whose third subcell is = 5

x=a{1,2};

plot(a{1,3}(x))

x=[-pi:0.01:pi];

plot(a{1,3}(x).^2)

*******************

STRUCTURES

-----------

Structures are data types that group together values that are logically

related in what are called fields of the structure.

An advantage of structures is that the fields are named, which helps

to make it clear what values are stored in the structure.

However, structure variables are not arrays. They do not have


elements that are indexed, so it is not possible to loop through

the values in a structure or to use vectorized code.

Creating and Modifying Structure Variables

An individual structure variable for a given software package might

look like this:

package

item_no cost price code

123 19.99 39.95 g

The name of the structure variable is package;

it has four fields: item_no, cost, price, and code.

One way to initialize a structure variable is to use the

struct function:

>> package = struct('item_no',123,'cost',19.99,'price',39.95,'code','g')

package =

item_no: 123

cost: 19.9900

price: 39.9500

code: 'g'

Note that in the Workspace Window, the variable package is listed as a 1 x 1

struct; the type of the variable is struct.


>> class(package)

ans =

struct

>> size(package)

ans =

1 1

%%%%

An alternative method of creating this structure, which is not as efficient,

involves using the dot operator to refer to fields within the structure:

>> package.item_no = 123;

>> package.cost = 19.99;

>> package.price = 39.95;

>> package.code = 'g';

An entire structure variable can be assigned to another:

>> newpack = package;

>> newpack.item_no = 111;

>> newpack.price = 34.95

newpack =

item_no: 111

cost: 19.9900
price: 34.9500

code: 'g'

To print from a structure, the disp function will display either the entire

structure or an individual field.

>> disp(package)

item_no: 123

cost: 19.9900

price: 39.9500

code: 'g'

>> disp(package.cost)

19.9900

However, using fprintf only individual fields can be printed; the entire

structure cannot be printed without referring to all fields individually.

>> fprintf('%6d %c\n', package.item_no, package.code)

123 g

The function rmfield removes a field from a structure:

>> Newpack=rmfield(newpack, 'code')

Newpack =

item_no: 111

cost: 19.9900
price: 34.9500

>> newpack

newpack =

item_no: 111

cost: 19.9000

price: 34.9500

code: 'g'

To change the value of newpack, the structure that results from

calling rmfield must be assigned to newpack.

>> newpack = rmfield(newpack, 'code')

newpack =

item_no: 111

cost: 19.9000

price: 34.9500

%%%%

Passing Structures to Functions

An entire structure variable can be passed to the function, which then

must use the dot operator to refer to the price and cost fields of the

input argument:

calcprof.m

--------------------------------------------------------

function profit = calcprof(packstruct)


% calcprofit calculates the profit for a

% software package

% packstruct - local name of an arbitrary structure

% Format: calcprof(structure w/ price & cost fields)

profit = packstruct.price - packstruct.cost;

end

--------------------------------------------------------

To call it, use as the argument of this function

the actual name of structure (package, or another)

>> calcprof(package)

ans =

19.9600

%%%

Alternatively, just the price and cost fields can be passed to the function

using the dot operator in the function call:

calcprof2.m

--------------------------------------------------

function profit = calcprof2(oneprice, onecost)

% Calculates the profit for a software package

% Format: calcprof2(price, cost)

profit = oneprice - onecost;

end

--------------------------------------------------

>> calcprof2(package.price, package.cost)

ans =

19.9600
*****

Related Structure Functions

The fieldnames function will return the names of the fields that are

contained in a structure variable:

>> pack_fields = fieldnames(package)

pack_fields =

'item_no'

'cost'

'price'

'code'

*******

Monday

Vectors of Structures

In many applications, including database applications, information would

normally be stored in a vector of structures, rather than in individual

structure variables. For example, if the Computer Super Mart is storing

information on all of the software packages that it sells, it would

likely be in a vector of structures such as the following:

packages

item_no cost price code


1 123 19.99 39.95 g

2 456 5.99 49.99 l

3 587 11.11 33.33 w

This vector of structures can be created as so:

packages(1)=struct('item_no',123,'cost',19.99,'price',39.95,'code','g');

packages(2)=struct('item_no',456,'cost', 5.99,'price',49.99,'code','l');

packages(3)=struct('item_no',587,'cost',11.11,'price',33.33,'code','w');

Both of these methods, however, involve extending the vector. As we have

already seen, preallocating any vector in MATLAB is more efficient than

extending it. There are several methods of preallocating the vector.

By starting with the last element, MATLAB would create a vector with

that many elements.

Then, the elements from 1 through end-1 could be initialized:

packages(3)=struct('item_no',587,'cost',11.11,'price',33.33,'code','w');

packages(1)=struct('item_no',123,'cost',19.99,'price',39.95,'code','g');

packages(2)=struct('item_no',456,'cost', 5.99,'price',49.99,'code','l');

To understand better:

If you do first:

packages(3) = struct('item_no',587,'cost',11.11,'price',33.33,'code','w');
then, if you type

packages(2)

ans =

item_no: []

cost: []

price: []

code: []

However, if you do first

packages(1) = struct('item_no',123,'cost',19.99,'price',39.95,'code','g');

then, if you type

packages(2)

Error: Index exceeds matrix dimensions.

%%%%%%%%%

Typing the name of the variable will display only the size of the

structure vector and the names of the fields:

>> packages

packages =

1x3 struct array with fields:


item_no

cost

price

code

To display one element in the vector (one structure), an index into the

vector should be specified:

>> packages(2)

ans =

item_no: 456

cost: 5.9900

price: 49.9900

code: 'l'

To refer to a field, it is necessary to refer to the particular structure,

and then the field within it:

>> packages(1).code

ans =

Thus, there are essentially three levels to this data structure.

The variable packages is the highest level, which is a vector of structures.

Each of its elements is an individual structure. The fields within these

individual structures are the lowest level.


The following loop displays each element in the packages vector:

>> for i = 1:length(packages)

disp(packages(i))

end

item_no: 123

cost: 19.9900

price: 39.9500

code: 'g'

item_no: 456

cost: 5.9900

price: 49.9900

code: 'l'

item_no: 587

cost: 11.1100

price: 33.3300

code: 'w'

For example, to print all of the costs, a for loop could be used:

for i=1:3

fprintf('%.3f\n',packages(i).cost)

end

19.990000
5.990000

11.110000

However, fprintf would do this automatically in MATLAB:

fprintf('%f\n',packages.cost)

19.990000

5.990000

11.110000

Using the dot operator to refer to all values of a field would result

in the values being stored successively in the default variable ans:

packages.cost

ans =

19.9900

ans =

5.9900

ans =

11.1100

However, the values can all be stored in a vector, as so:

pc = [packages.cost]

pc =

19.9900 5.9900 11.1100


*****

To sum all three cost fields, the vector of cost fields is passed to the sum function:

sum([packages.cost])

ans =

37.0900

% function input is a vector of structures

The following is an example of a function that receives the entire

vector of structures as an input argument and prints all of it in

a nice table format:

printpackages.m

----------------------------------------------------

function printpackages(packstruct)

% printpackages prints a table showing all

% values from a vector of 'packages' structures

% Format: printpackages(package structure)

fprintf('\nItem # Cost Price Code\n')

no_packs = length(packstruct);

for i = 1:no_packs

fprintf('%6d %6.2f %6.2f %4c\n', ...

packstruct(i).item_no, ...

packstruct(i).cost, ...
packstruct(i).price, ...

packstruct(i).code)

end

end

----------------------------------------------------

An example of calling the function follows:

printpackages(packages)

Item # Cost Price Code

123 19.99 39.95 g

456 5.99 49.99 l

587 11.11 33.33 w

%%%%

As another example, consider a database of information that a professor

might store for the class. The vector structure variable, called student,

might look like the following:

student

name id_no quiz

1 2 3 4

1 Conte,Joe 999 10.0 9.5 0.0 10.0

2 Hernandez, Pete 784 10.0 10.0 9.0 10.0

3 Brown, Violet 332 7.5 6.0 8.5 7.5

This data structure could be defined as follows:


student(3)=struct('name','Brown,Violet','id_no',332,'quiz',[7.5 6 8.5 7.5]);

student(1)=struct('name','Conte, Joe','id_no',999,'quiz',[10 9.5 0 10]);

student(2)=struct('name','Hernandez, Pete','id_no',784,'quiz',[10 10 9 10]);

Once the data structure has been initialized, in MATLAB we could refer to

different parts of it. The variable student is the entire array;

MATLAB just shows the names of the fields.

>> student

student =

1x3 struct array with fields:

name

id_no

quiz

To see the actual values, one would refer to individual structures

and/or fields:

>> student(1)

ans =

name: 'Conte, Joe'

id_no: 999

quiz: [10 9.5000 0 10]

>> student(1).quiz

ans =
10.0000 9.5000 0 10.0000

>> student(1).quiz(2)

ans =

9.5000

>> student(3).name(1)

ans =

The following are examples of expressions that refer to different

parts of this data structure:

- student is the entire data structure, which is a vector of structures

- student(1) is an element from the vector, which is an individual structure

- student(1).quiz is the quiz field from the structure,

which is a vector of double values

- student(1).quiz(2) is an individual double quiz grade

- student(3).name(1) is the first letter of the third student’s name.

%%%%%%%%

For example, let's write a function that calculates and prints the

average quiz grade

printAves.m

-----------------------------------------------------

function printAves(student)
% This function prints the average quiz grade

% for each student in the vector of structs

% Format: printAves(student array)

fprintf('%-20s %s\n', 'Name', 'Average')

for i = 1:length(student)

qsum = sum(student(i).quiz); %sum of all grades of student "i"

no_quizzes = length(student(i).quiz); %length of a quiz array

ave = qsum/no_quizzes;

fprintf('%-20s %.1f\n', student(i).name, ave);

end

end

-----------------------------------------------------

Here is an example of calling the function:

>> printAves(student)

Name Average

Conte, Joe 7.4

Hernandez, Pete 9.8

Brownnose, Violet 7.4

******

Nested Structures

A nested structure is a structure in which at least one member is itself

a structure. An example in a structure for a line segment:


lineseg

endpoint1 endpoint2

x y x y

2 4 1 6

One method of defining this is to nest calls to the struct function:

lineseg=struct('endpoint1',struct('x',2,'y',4),'endpoint2',struct('x',1,'y',6))

Once the nested structure has been created, we can refer to different

parts of the variable lineseg. Just typing the name of the variable

shows only that it is a structure consisting of two fields,

endpoint1 and endpoint2, each of which is a structure:

>> lineseg

lineseg =

endpoint1: [1x1 struct]

endpoint2: [1x1 struct]

Typing the name of one of the nested structures will display the field names

and values within that structure:

>> lineseg.endpoint1

ans =

x: 2
y: 4

Using the dot operator twice will refer to an individual coordinate,

such as in the following example:

>> lineseg.endpoint1.x

ans =

Let's calculate the distance between these two points:

P1=[lineseg.endpoint1.x lineseg.endpoint1.y];

P2=[lineseg.endpoint2.x lineseg.endpoint2.y];

P1 =

2 4

P2 =

1 6

d=sqrt((P2(1)-P1(1))^2+(P2(2)-P1(2))^2);

or

d=norm(P2-P1)
d=

2.2361

******

Vectors of Nested Structures

Combining vectors and nested structures, it is possible to have a vector of

structures in which some fields are structures themselves. Here is an example

in which a company manufactures cylinders from different materials for

industrial use:

cyls

code dimensions weight

rad height

1 x 3 6 7

2 a 4 2 5

3 c 3 6 9

Here is an example of initializing the data structure by preallocating:

cyls(3)=struct('code','c','dimensions',struct('rad',3,'height',6),'weight',9);

cyls(1)=struct('code','x','dimensions',struct('rad',3,'height',6),'weight', 7);

cyls(2)=struct('code','a','dimensions',struct('rad',4,'height',2),'weight', 5);

For these cylinders, one desired calculation may be the volume of each

cylinder, which is defined as pi * r^2 * h, where r is the radius and h

is the height:
printcylvols.m

----------------------------------------------------------

function printcylvols(cyls)

% printcylvols prints the volumes of each cylinder

% in a specialized structure

% Format: printcylvols(cylinder structure)

% It calls a subfunction to calculate each volume

for i = 1:length(cyls)

vol = cylvol(cyls(i).dimensions);

fprintf('Cylinder %c has a volume of %.1f in^3\n', cyls(i).code, vol);

end

end

function cvol = cylvol(dims)

% cylvol calculates the volume of a cylinder

% Format: cylvol(dimensions struct w/ fields 'rad', 'height')

cvol = pi * dims.rad ^ 2 * dims.height;

end

----------------------------------------------------------

The following is an example of calling this function.

>> printcylvols(cyls)

Cylinder x has a volume of 169.6 in^3

Cylinder a has a volume of 100.5 in^3

Cylinder c has a volume of 169.6 in^3

You might also like