MATLAB完全自学教程
上QQ阅读APP看书,第一时间看更新

2.9 单元数组和结构体

单元数组(cell array)和结构体(structure)都可以将不同类型的相关数据集成到一个单一的变量中,使得大量的相关数据的处理变得非常简单而且方便。但是,需要注意的是,单元数组和结构体只是承载其他类型数据的容器,大部分的数学运算则只是针对两者中具体的数据进行,而不是针对单元数组或结构体本身进行。

单元数组中的每一个单元都是通过数字来进行索引的,但用户需要加入一个单元或者从一个单元中提取数据时,需要给出单元数组中该单元的索引。结构体和单元数组十分相似,两者的主要区别在于结构体中的数据存储并不是由数字来表示的,而是通过结构体中的名称来表示的。

2.9.1 单元数组的创建和操作

单元数组中的单个元素称为单元(cell)。单元中的数据可以为任何数据类型,包括数值数组、字符、符号对象、其他单元数组或结构体等。不同单元中的数据的数据类型可以不同。从理论上来讲,可以创建任意维数的单元数组。大多数情况下,为了方便,创建简单的单元数组(如一维单元数组)。单元数组的创建方法分为两种:通过赋值语句直接创建;通过cell()函数首先为单元数组分配内存空间,然后对每个单元进行赋值。如果工作空间内的某个变量名与所创建的单元数组同名,那么此时则不会对单元数组赋值。

直接通过赋值语句创建单元数组时,有两种方法可以采用,即按单元索引法和按内容索引法(其实就是将花括号“{}”放在等式的右边或左边的区别)。采用按单元索引法赋值时,用标准数组的赋值方法,赋值时赋给单元的数值通过花括号“{}”将单元内容括起来。采用按内容索引法赋值时,将花括号“{}”写在等号左边,即放在单元数组名称后。

2.64 举例说明两种赋值方法。

>> clear A      %采用按单元索引法赋值
>> A(1,1)={[1 2 3;4 5 6; 7 8 9]}
A =
[3x3 double]
>> A(1,2)={1+2i}
A =
[3x3 double]    [1.0000 + 2.0000i]
>> A(2,1)={'hello world'}
A =
[3x3 double]    [1.0000 + 2.0000i]
'hello world'                    []
>> A(2,2)={0:pi/3:pi}
A =
[3x3 double]    [1.0000 + 2.0000i]
'hello world'          [1x4 double]
>> clear B      %采用按内容索引法赋值
>> B{1,1}=[1 2 3;4 5 6;7 8 9]
B =
[3x3 double]
>> B{1,2}=3+4i
B =
[3x3 double]    [3.0000 + 4.0000i]
>> B{2,1}='hello world'
B =
[3x3 double]    [3.0000 + 4.0000i]
'hello world'                    []
>> B{2,2}=0:2:9
B =
[3x3 double]    [3.0000 + 4.0000i]
'hello world'          [1x5 double]
>> A{2,2}
ans =
0    1.0472    2.0944    3.1416
>> A(2,2)
ans =
[1x4 double]

按单元索引法和按内容索引法是完全等效的,可以互换使用。通过上面的例子,我们可以看出“{}”用于访问单元的值,而“()”用于标识单元(不用于访问单元的值)。具体理解“{}”和“()”的区别可以在例2.64的代码的最后分别输入A{2,2}A(2,2),就会发现使用“{}”能显示完整的单元内容,而使用“()”有时无法显示完整的单元内容。如果需要将单元数组的所有内容都显示出来,可以采用celldisp()函数来强制显示单元数组的所有内容。

如下面的程序。

>> B{2,2}
ans =
0     2     4     6     8
>> B(2,2)
ans =
[1x5 double]
>> B{2,:}
ans =
hello world
ans =
0     2     4     6     8
>> B(2,:)
ans =
'hello world'    [1x5 double]

创建单元数组的另一种方法是使用 cell()函数。在创建时,可以采用 cell()函数生成空的单元数组,为单元数组分配内存,然后向单元数组中存储数据。存储数据时,可以采用按内容索引法或按单元索引法来进行赋值,如下面的程序。

>> C=cell(2,3)
C =
[]    []    []
[]    []    []
>> C{1,1}=randperm(5)
C =
[1x5 double]    []    []
[]    []    []
>> C{1,2}='He is a student'
C =
[1x5 double]    'He is a student'    []
[]                   []    []
>> C(2,3)={[1 2;3 4]}
C =
[1x5 double]    'He is a student'              []
[]                   []    [2x2 double]

单元数组还可以通过扩展的方法来得到进一步的扩展。如利用方括号将多个单元数组组合在一起,从而形成维数更高的单元数组。如果想要获得单元数组的子集的内容,则可以利用数组索引的方法,将数组的子集提取出来并赋予新的单元数组。要删除单元数组中的某一部分内容,可以将这部分内容设置为空数组,即可删除,如下面的程序。

>> C=[A;B]
C =
[3x3 double]    [1.0000 + 2.0000i]
'hello world'          [1x4 double]
[3x3 double]    [3.0000 + 4.0000i]
'hello world'          [1x5 double]
>> E=C([1 4],:)
E =
[3x3 double]    [1.0000 + 2.0000i]
'hello world'          [1x5 double]
>> C(3,:)=[]
C =
[3x3 double]    [1.0000 + 2.0000i]
'hello world'          [1x4 double]
'hello world'          [1x5 double]

在单元数组的操作中,可以利用reshape()函数来改变单元数组的结构。经过reshape()函数对单元数组进行处理后,单元数组的内容并不增多或减少,即单元数组改变前后的总单元数目并不发生变化。

2.65 利用repmat()函数复制单元数组。

>> A=cell(4,5);
>> size(A)     %计算单元数组A的大小
ans =
4     5
>> B=reshape(A,5,4)      %改变结构后的单元数组
B =
[]    []    []    []
[]    []    []    []
[]    []    []    []
[]    []    []    []
[]    []    []    []
>> C=repmat(B,1,3)
C =
[]    []    []    []    []    []    []    []    []    []    []    []
[]    []    []    []    []    []    []    []    []    []    []    []
[]    []    []    []    []    []    []    []    []    []    []    []
[]    []    []    []    []    []    []    []    []    []    []    []
[]    []    []    []    []    []    []    []    []    []    []    []

2.9.2 单元数组处理函数

MATLAB提供了单元数组处理函数,如表2-12所示。

表2-12 单元数组处理函数

2.66 举例说明单元数组处理函数的用法。

>> a=ones(3,4);
>> b=zeros(3,2);
>> c=(5:6)';
>> X={a b c}
X =
[3x4 double]    [3x2 double]    [2x1 double]
>> celldisp(X)
X{1} =
1     1     1     1
1     1     1     1
1     1     1     1
X{2} =
0     0
0     0
0     0
X{3} =
5
6
>> [i,j,k]=deal(X{:})
i =
1     1     1     1
1     1     1     1
1     1     1     1
j =
0     0
0     0
0     0
k =
5
6
>> cellfun('isreal',X)
ans =
1     1     1
>> a=randn(3,4)
a =
-1.0866   -0.3416    0.1684   -0.5453
0.9679    0.4884   -0.3924   -0.6330
-0.5865   -0.7801   -0.0458   -1.6788
>> b=num2cell(a,1)
b =
Columns 1 through 3
[3x1 double]    [3x1 double]    [3x1 double]
Column 4
[3x1 double]
>> b=num2cell(a,1)
b =
[3x1 double]    [3x1 double]    [3x1 double]    [3x1 double]
>> c=num2cell(a)
c =
[-1.0866]    [-0.3416]    [ 0.1684]    [-0.5453]
[ 0.9679]    [ 0.4884]    [-0.3924]    [-0.6330]
[-0.5865]    [-0.7801]    [-0.0458]    [-1.6788]

2.9.3 结构体创建

结构体和单元数组非常相似,也是将不同类型的数据集中在一个单独的变量中,结构体通过字段(fields)来对元素进行索引,在访问时只需通过“. ”来访问数据变量。结构体可以通过两种方法进行创建,即通过直接赋值方法创建或通过struct()函数创建。

2.67 结构体创建函数的用法介绍。

>> circle.radius=4;
>> circle.center=[0 0];
>> circle.color='red';
>> circle.linestyle='--';
>> circle.linestyle='--'
circle =
radius: 4
center: [0 0]
color: 'red'
linestyle: '--'
>> circle(2).radius=5;
>> circle(2).center=[1 1];
>> circle(2).color='blue';
>> circle(2).linestyle='…'
circle =
1x2 struct array with fields:
radius
center
color
linestyle
>> circle(1).filled='yes'
circle =
1x2 struct array with fields:
radius
center
color
linestyle
filled
>> circle.filled
ans =
yes
ans =
[]
>> data1={4,5,'sqrt(6)'};
>> data2={[0,0] [1,1] [4 5]};
>> data3={'--' '...' '-.-.'};
>> data4={'red' 'blue' 'yellow'};
>> data5={'yes' 'no' 'no'};
>> circle=struct('radius',data1,'center',data2,'linestyle',data3,'color',data4,'filled', data5)
circle =
1x3 struct array with fields:
radius
center
linestyle
color
filled

2.9.4 结构体处理函数

结构体作为一种特殊的数组类型,具有和数值型数组和单元数组相同的处理方式。通过结构体处理函数,可以很方便地对结构体数据进行处理。MATLAB提供了一些常用的结构体处理函数,如表2-13所示。

表2-13 结构体处理函数

2.68 结构体处理函数的用法介绍。

>> circle
circle =
1x3 struct array with fields:
radius
center
linestyle
color
filled
>> center=cat(1,circle.center)
center =
0     0
1     1
4     5
>> [a1,a2,a3]=deal(circle.color)
a1 =
red
a2 =
blue
a3 =
yellow
>> [circle.radius]=deal(12,34,56)
circle =
1x3 struct array with fields:
radius
center
linestyle
color
filled
>> circle.radius
ans =
12
ans =
34
ans =
56
>> fieldnames(circle)
ans =
'radius'
'center'
'linestyle'
'color'
'filled'
>> isfield(circle,'radius')
ans =
1
>> orderfields(circle)
ans =
1x3 struct array with fields:
center
color
filled
linestyle
radius
>> circle_new=rmfield(circle,'filled')
circle_new =
1x3 struct array with fields:
radius
center
linestyle
color