精通MATLAB(第3版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3章 数组及其操作

在MATLAB内部的任何数据类型,都是按照数组的形式进行存储和运算的。这里说的数组是广义的,它可以只有一个元素,也可以是一行或一列元素,还可能就是最普通的二维数组,抑或高维空间的多维数组;其元素也可以是任意数据类型,如数值型、逻辑型、字符串型,或元胞型等。

理解数组概念及其各种运算和操作,是学习MATLAB时的一个重要问题。本章以数值类型的一维和二维数组为例,重点讲解MATLAB中数组的概念和属性,以及创建、裁剪、寻址和运算等多种基本数组操作,这对于其他数据类型的数组,大部分都是通用的,因此读者要熟练掌握本章讲述的概念和操作函数。

3.1 MATLAB中的数组

MATLAB中数组可以说无处不在,任何变量在MATLAB中都是以数组形式存储和运算的。

按照数组元素个数和排列方式,MATLAB中的数组可以分为:

(1)没有元素的空数组(empty array)。

(2)只有一个元素的标量(scalar),它实际上是一行一列的数组。

(3)只有一行或者一列元素的向量(vector),分别叫做行向量和列向量,也统称为一维数组。

(4)普通的具有多行多列元素的二维数组。

(5)超过二维的多维数组(具有行、列、页等多个维度,详见本书第4章)。

按照数组的存储方式,MATLAB中的数组可以分为普通数组和稀疏数组(常称为稀疏矩阵)。稀疏矩阵适用于那些大部分元素为0,只有少部分非零元素的数组的存储,主要是为了提高数据存储和运算的效率。本书的第14章将介绍稀疏矩阵的部分内容。

3.2 数组的创建

MATLAB中一般使用方括号([])、逗号(,)或空格,以及分号(;)来创建数组,方括号中给出数组的所有元素,同一行中的元素间用逗号或空格分隔,不同行之间用分号分隔。

3.2.1 创建空数组

空数组是MATLAB中特殊的数组,它不含有任何元素。空数组可以用于数组声明,数组清空,以及各种特殊的运算场合(如特殊的逻辑运算,详见本书第8章)。

创建空数组很简单,只需要把变量赋值为空的方括号即可。

例3-1 创建空数组A。

>> A=[];
A = []

3.2.2 创建一维数组

一维数组包括行向量和列向量,是所有元素排列在一行或一列中的数组。实际上,一维数组可以看做二维数组在某一方向(行或列)尺寸退化为1的特殊形式。

创建一维行向量,只需要把所有用空格或逗号分隔的元素用方括号括起来即可;而创建一维列向量,则需要在方括号括起来的元素之间用分号分隔。不过,更常用的办法是用转置运算符('),把行向量转置为列向量。

例3-2 创建行向量和列向量。

>> A=[1 2 3 4];
A = 1 2 3 4
>> B=[1;2;3;4];
B =
    1
    2
    3
    4
1.通过冒号(:)创建

很多时候要创建的一维数组实际上是个等差数列,这时候可以通过冒号(:)来创建。例如:

Var=start_val:step:stop_val

表示创建一个一维行向量Var,它的第一个元素是start_val,然后依次递增(step为正)或递减(step为负)step,直到向量中的最后一个元素与stop_val差的绝对值小于等于step的绝对值为止。当不指定step时,默认step等于1。

2.通过linspace函数创建

和冒号功能类似的是MATLAB提供的linspace函数:

Var=linspace(start_val,stop_val,n)

表示创建一个一维行向量Var,它的第一个元素是start_val,最后一个元素是stop_val,形成总共是n个元素的等差数列。不指定n时,默认n等于100。要注意,这和冒号是不同的,冒号创建等差的一维数组时,stop_val可能取不到。

一维列向量可以通过一维行向量的转置(')得到。

例3-3 创建一维等差数组。

>> A=1:4;
A = 1 2 3 4
>> B=1:2:8;
B = 1 3 5 7
>> D=linspace(1,4,5);
D = 1.0000 1.7500 2.5000 3.2500 4.0000
3.通过logspace函数创建

类似于linspace函数,MATLAB中还有创建等比一维数组的logspace函数:

Var=logspace(start_val,stop_val,n)

表示产生从10^start_val到10^stop_val包含n个元素的等比一维数组Var。不指定n时,默认n等于50。

例3-4 创建一维等比数组。

>> A=logspace(0,log10(32),6);
A = 1.0000 2.0000 4.0000 8.0000 16.0000 32.0000

创建一维数组可能用到:方括号、逗号或空格、分号、冒号、函数linspace和logspace,以及转置符号(')。

3.2.3 创建二维数组

常规创建二维数组的方法实际上和创建一维数组方法类似,就是综合运用方括号、逗号、空格,以及分号。方括号把所有元素括起来,不同行元素之间用分号间隔,同一行元素之间用逗号或者空格间隔,按照逐行排列的方式顺序书写每个元素。当然,在创建每一行或列元素的时候,可以利用冒号和函数的方法,只是要特别注意创建二维数组时,要保证每一行(或每一列)具有相同数目的元素。

例3-5 创建二维数组。

>> A=[1 2 3;2 5 6;1 4 5];
A =
    1 2 3
    2 5 6
    1 4 5
>> B=[1:5;linspace(3,10,5);3 5 2 6 4];
B =
   1.0000 2.0000 3.0000 4.0000 5.0000
   3.0000 4.7500 6.5000 8.2500 10.0000
   3.0000 5.0000 2.0000 6.0000 4.0000
>> C=[[1:3]' [linspace(2,3,3)]' [3 5 6]'];
C =
   1.0000 2.0000 3.0000
   2.0000 2.5000 5.0000
   3.0000 3.0000 6.0000

创建二维数组,也可以通过函数拼接一维数组,或者利用MATLAB内部函数直接创建特殊的二维数组,这些在本章后续内容中会逐步介绍。

3.3 数组属性

MATLAB中提供了大量的函数,用于返回数组的各种属性,包括数组的排列结构、数组的尺寸大小、维度、数组数据类型,以及数组的内存占用情况等。

3.3.1 数组结构

数组的结构指的是数组中元素的排列方式,MATLAB中的数组实际上就分为本章3.1节中介绍的几种。MATLAB中提供了多种测试函数。

(1)isempty检测某个数组是否是空数组。

(2)isscalar检测某个数组是否是单元素的标量数组。

(3)isvector检测某个数组是否是具有一行或一列元素的一维向量数组。

(4)issparse检测某个数组是否是稀疏矩阵。

这些测试函数都是以is开头,然后紧跟检测的内容的关键字,它们的返回结果为逻辑类型,返回1表示测试符合条件,返回0表示测试不符合条件。关于稀疏矩阵的测试,本书第14章将进行讲解,这里只示例前几个数组结构的测试函数。

例3-6 数组结构测试函数。

>> A=32;
A = 32
>> isscalar(A);
ans = 1
>> B=1:5;
B = 1 2 3 4 5
>> isvector(B);
ans = 1
>> isempty(B);
ans = 0

3.3.2 数组大小

数组大小是数组的最常用属性,它是指数组在每一个方向上具有的元素个数。例如,对于含有10个元素的一维行向量数组,则它在行的方向上(纵向)只有1个元素(1行),在列的方向上(横向)则有10个元素(10列)。

MATLAB中最常用的返回数组大小的是size函数。size函数有多种用法,对于一个m行n列的数组A,可以按以下两种方式使用size函数。

(1)d=size(A)

将数组A的行列尺寸以一个行向量的形式返回给变量d,即d=[m n];

(2)[a,b]=size(A)

将数组A在行、列的方向的尺寸返回给a,b,即a=m,b=n。

length函数常用于返回一维数组的长度。

①当A是一维数组时,length(A)返回此一维数组的元素个数;

②当A是普通二维数组时,length(A)返回size(A)得到的两个数中较大的那个。

在MATLAB中,空数组被默认为行的方向和列的方向尺寸都为0的数组,但如果自定义产生的多维空数组,则情况可能不同。

MATLAB中还有返回数组元素总个数的函数numel,对于m行n列的数组A,numel(A)实际上返回m*n。

例3-7 数组大小。

>> A=[];
A = []
>> size(A);
ans = 0 0
>> B=[1 2 3 4 5];
B = 1 2 3 4 5
>> length(B);
ans = 5
>> C=[1:5;2:6];
C =
    1 2 3 4 5
    2 3 4 5 6
>> size(C);
ans = 2 5
>> length(C);
ans = 5
>> numel(C);
ans = 10

通过例3-7可以看出,MATLAB通常把数组都按照普通的二维数组对待,即使是没有元素的空数组,也有行和列两个方向,只不过在这两个方向上它的尺寸都是零;而一维数组则是在行或者列中的一个方向的尺寸为1;标量则在行和列两个方向上的尺寸都是1。

3.3.3 数组维度

通俗一点讲数组维度,就是数组具有的方向。比如普通的二维数组,数组具有行的方向和列的方向,就是说数组具有两个方向,是一个二维数组。MATLAB中还可以创建三维甚至更高维的数组。

对于空数组、标量和一维数组,MATLAB还是当做普通二维数组对待的,因此它们都至少具有两个维度(至少具有行和列两个方向)。特别的,用空白方括号产生的空数组是当做二维数组对待的,但在高维数组中也有空数组的概念,这时候的空数组可以是只在任意一个维度上尺寸等于零的数组,相应地,此时的空数组就具有多个维度了。

MATLAB中计算数组维度可以用函数ndims。

ndims(A)返回结果实际上等于length(size(A))。

例3-8 数组维度。

>> B=2;
B = 2
>> ndims(B);
ans = 2
>> C=1:5;
C = 1 2 3 4 5
>> ndims(C);
ans = 2

通过例3-8可以看到,一般的非多维数组,在MATLAB中都是当做二维数组处理的。

3.3.4 数组数据类型

数组作为一种MATLAB的内部数据存储和运算结构,其元素可以是各种各样的数据类型(关于数据类型,可以参考本书第5、6、7章)。对应于不同的数据类型的元素,可以有数值数组(实数数组、浮点数值数组、整数数组等)、字符数组、元胞数组、字符串的元胞数组、结构体数组等,MATLAB中提供了测试一个数组是否是这些类型的数组的测试函数,如表3-1所示。

表3-1 数组数据类型测试函数

在表3-1中,所有的测试函数同样都是以is开头,紧跟着一个测试内容关键字,它们的返回结果依然是逻辑类型,返回0表示不符合测试条件,返回1表示符合测试条件。

例3-9 数组数据类型测试函数。

>> A=[1 2;3 5];
A =
    1 2
    3 5
>> isnumeric(A);
ans = 1
>> isreal(A);
ans = 1
>> isfloat(A);
ans = 1

例3-9中用几个整数赋值的数组A,实际上它的每一个元素都被当做双精度浮点数存储和运算(参考本书第5章),因此,测试发现数组A是一个实数数组、浮点数数组,而不是整数数组,更不是字符数组。这些测试函数在本书的后续章节还有所涉及。

3.3.5 数组的内存占用

了解数组的内存占用情况,对于优化MATLAB代码的性能是重要的。用户可以通过whos命令查看当前工作区中所有变量或指定变量的多种信息,包括变量名、数组大小、内存占用和数组元素的数据类型等。

例3-10 数组的内存占用。

>> A=[3 2 5];
A = 3 2 5
>> whos;
  Name Size Bytes Class
  A 1x3 24 double array
Grand total is 3 elements using 24 bytes

不同数据类型的数组的单个元素,内存占用是不一样的,用户可以通过whos命令计算各种数据类型的变量占用内存的情况,如例3-10中,1行3列的双精度浮点型数组A,占用内存24字节,那么每一个双精度浮点型的元素就占用了8字节的内存空间。

通过简单的whos命令,用户就可以了解MATLAB中各种数据类型的内存占用情况,当然,读者也可以直接参考本书第5章学习不同数据类型变量的差别。

3.4 创建特殊数组

在矩阵代数领域,用户经常需要创建具有一定形式的特殊数组。MATLAB提供了丰富的创建特殊数组的函数。

3.4.1 0-1数组

顾名思义,0-1数组就是所有元素不是0就是1的数组。在线性代数中,经常用到的0-1数组有:

(1)所有元素都为0的全0数组。

(2)所有元素都为1的全1数组。

(3)只有主对角线元素为1,其他位置元素全部为0的单位数组。

(4)此外就是一般的0-1数组。

MATLAB中,有专门的函数可以创建这些标准数组。

(1)zeros(m,n):创建一个m行n列的全0数组,也可以用zeros(size(A))创建一个和A具有相同大小的全0数组。如果只指定一个数值,zeros(m)则创建一个m行m列的全0数组。

(2)ones(m,n):ones(m,n)和ones(size(A))则是创建m行n列,或者与A尺寸相同的全1数组。而 ones(m)也是创建一个m行m列的全1数组。

(3)eye:用法和zeros、ones类似,不过创建的是指定大小的单位数组,即只有主对角线元素为1,其他元素全为0。

例3-11 创建0-1数组。

>> A=zeros(2); %创建二维的全零方阵
A =
    0 0
    0 0
>> B=ones(2,4);
B =
    1 1 1 1
    1 1 1 1
>> C=eye(size(A));
C =
    1 0
    0 1

3.4.2 对角数组

在有些情况下,需要创建对角线元素为指定值,其他元素都为0的对角数组。这就要用到diag函数。

一般diag函数接收一个一维行向量数组为输入参数,将此向量的元素逐次排列在所指定的对角线上,其他位置则用0填充。

(1)diag(v):创建一个对角数组,其主对角线元素依次对应于向量v的元素。

(2)diag(v,k):创建一个对角数组,其第k条对角线元素对应于向量v的元素。

  • 当k大于0时,表示主对角线向右上角偏离k个元素位置的对角线。
  • 当k小于0时,表示主对角线向左下角偏离k个元素位置的对角线。
  • 当k等于0时,则和diag(v)一样。

diag函数也可以接受普通二维数组形式的输入参数,此时就不是创建对角数组了,而是从已知数组中提取对角元素组成一个一维数组。

(1)diag(X)提取二维数组X的主对角线元素组成一维数组。

(2)diag(X,k)提取二维数组X的第k条对角线元素组成的一维数组。

组合这两种用法,很容易产生已知数组X的指定对角线元素对应的对角数组,只需要通过组合命令diag(diag(X,m),n),就可以提取X的第m条对角线元素,产生与此对应的第n条对角线元素为提取的元素的对角数组。

例3-12 创建对角数组。

>> A=diag([1 2 3]);
A =
    1 0 0
    0 2 0
    0 0 3
>> B=diag([1 2 3],2);
B =
    0 0 1 0 0
    0 0 0 2 0
    0 0 0 0 3
    0 0 0 0 0
    0 0 0 0 0
>> C=[3 5 1 2;2 4 5 6];
C =
    3 5 1 2
    2 4 5 6
>> diag(C);
ans =
    3
    4
>> D=diag(diag(C),-1); %注意,k=-1
D =
    0 0 0
    3 0 0
    0 4 0

这种组合使用两次diag函数产生对角数组的方法是常用的,读者需要加以掌握。

3.4.3 随机数组

在各种分析领域,随机数组都是很有用途的。MATLAB中可以通过内部函数产生服从多种随机分布的随机数组,常用的有均匀分布和正态分布的随机数组。

(1)rand(m,n)可以产生m行n列的随机数组,其元素服从0到1的均匀分布。

(2)rand(size(A))产生和数组A具有相同大小的、元素服从0到1均匀分布的随机数组。

(3)rand(m)则产生m行m列的元素服从0到1均匀分布的随机数组。

randn函数用于产生元素服从标准正态分布的随机数组,其用法和rand类似,此处不再赘述。

例3-13 创建随机数组。

>> A=rand(2);
A =
   0.9501 0.6068
   0.2311 0.4860
>> B=rand(2,4);
B =
   0.8913 0.4565 0.8214 0.6154
   0.7621 0.0185 0.4447 0.7919
>> C=randn(size(A));
C =
   -0.4326 0.1253
   -1.6656 0.2877

3.4.4 魔方数组

魔方数组也是一种比较常用的特殊数组,这种数组一定是正方形的(即行的方向的元素个数和列的方向的相等),而且每一行、每一列的元素之和都相等。

MATLAB可以通过magic(n)创建n行n列的魔方数组。

例3-14 创建魔方数组。

>> magic(3)
ans =
    8 1 6
    3 5 7
    4 9 2

读者可以自行验证,在例3-14中创建的魔方数组,其各行各列的算术和都是相等的。

利用MATLAB函数,除了可以创建这些常用的标准数组外,也可以创建许多专门应用领域常用的特殊数组,这将在本书第14章中作进一步介绍。

3.5 数组操作

前面讲解了MATLAB中数组的创建方法和基本属性,本节重点介绍在实际应用中最常用的一些数组操作方法。

3.5.1 数组的保存和装载

许多实际应用中的数组都是很庞大的,而且当操作步骤较多,不能在短期内完成,需要多次分时进行时,这些庞大的数组的保存和装载就是一个重要问题了,因为每次在进行操作前对数组进行声明和赋值,需要很庞大的输入工作量。一个好的解决方法是将数组保存在文件中,每次需要时进行装载。

MATLAB中提供了内置的把变量保存在文件中的方法,最简单易用的是将数组变量保存为二进制的.mat文件。用户可以通过save命令将工作区中指定的变量存储在.mat文件中。

(1)save命令的一般语法是:

save <filename> <var1> <var2>…<varN>

其作用是把var1 var2…varN指定的工作区变量存储在filename指定名称的.mat文件中。

通过save存储到.mat文件中的数组变量,在使用前可以用load命令装载到工作区。

(2)load命令的一般语法是:

load <filename> <var1> <var2>…<varN>

其作用是把当前目录下存储在filename.mat文件中的var1 var2…varN指定的变量装载到MATLAB工作区中。

关于save和load在数据保存和装载方面的更详细的内容,读者可以参考本书第12章。

3.5.2 数组索引和寻址

数组操作中最频繁遇到的就是对数组的某个具体位置上的元素进行访问和重新赋值,这涉及定位数组中元素位置,也就是数组索引和寻址的问题。

MATLAB中数组元素的索引方式包括数字索引和逻辑索引两类。

1.数字索引方式

MATLAB中,普通二维数组元素的数字索引方式又可以分为两种:双下标(也叫全下标)索引和单下标索引。

双下标索引方式,顾名思义,就是用两个数字(自然数)来定位元素的位置。实际上就是用一个有序数对来表征元素位置,第一个数字指定元素所在的行位置,第二个数字指定元素所在的列。

两个表示元素位置的索引数字之间用逗号分隔,并用圆括号括起来,紧跟在数组变量名后,就可以访问此数字索引指定的位置上的数组元素了。

例如,对于3行2列的数组A,A(3,1)表示数组A的第3行第1列的元素,A(1,2)表示数组A的第1行第2列的元素。

相应的,单下标索引方式就是用一个数字来定位数组元素。实际上,单下标索引和双下标索引是一一对应的,对一个已知尺寸的数组,任意一个单下标索引数字都可以转换成确定的双下标索引。对于m行n列的数组A,A(x,y)实际上对应于A((y-1)*m+x)。

例如,对于3行2列的数组A,A(3,1)用单下标索引表示就是A(3),A(1,2)用单下标索引表示就是A(4)。

MATLAB中单下标索引方式实际上采用了列元素优先的原则,即对于m行n列的数组A,第一列的元素的单下标索引依次为A(1),A(2),A(3),…,A(m),第二列的元素的单下标索引依次为A(m+1),A(m+2),A(m+3),…,A(2m),依此类推。

这两种数字索引方式中的数字索引也可以是一个数列,从而实现访问多个数组元素的目的,这通常可以通过应用冒号或一维数组来实现。

例3-15 数组元素的索引与寻址。

>> A=[4 2 5 6;3 1 7 0;12 45 78 23]; %创建数组
A =
    4 2 5 6
    3 1 7 0
    12 45 78 23
>> A(2,3); %双下标索引访问数组第2行第3列元素
ans = 7
>> A(2); %单下标索引访问数组第2个元素(即第2行第1列)
ans = 3
>> A(7); %单下标索引访问数组第7个元素(即第1行第3列)
ans = 5
>> A(3:5); %单下标索引访问数组第3到5位的元素(即第1列第3行和第2列第1、2行)
ans = 12 2 1
>> A(2,1:4) %双下标索引访问数组第2行,第1到4列的元素
ans = 3 1 7 0
>> A([3,1],2) %双下标索引访问数组第3、第1行,第2列的元素
ans =
    45
     2
>> A([3,1],[2,1]) %双下标索引访问数组第3、第1行,第2、第1列的元素
ans =
    45 12
     2 4
>> A(7)=100 %对数组第7个元素(即第1行第3列)重新赋值
A =
     4 2 100 6
     3 1 7 0
    12 45 78 23

通过例3-15可以看到,利用下标索引的方法,用户可以访问特定位置上的数组元素的值,或者对特定位置的数组元素重新赋值。

2.单下标索引和双下标索引的转换

单下标索引和双下标索引之间,可以通过MATLAB提供的函数进行转换。

(1)双下标索引→单下标索引

把双下标索引转换为单下标索引,需要用sub2ind命令,其语法为:

IND = sub2ind(siz,I,J)

其中siz是一个1行2列的数组,指定转换数组的行列尺寸,一般可以用size(A)来表示;I和J分别是双下标索引中的两个数字;IND则为转换后的单下标数字。

(2)单下标索引→双下标索引

把单下标索引转换为双下标索引,需要用ind2sub命令,其语法为:

[I,J] = ind2sub(siz,IND)

各变量意义同上。

例3-16 单-双下标转换。

>> A =[0.4057 0.4103 0.3529 0.1389 0.6038;
        0.9355 0.8936 0.8132 0.2028 0.2722;
        0.9169 0.0579 0.0099 0.1987 0.1988];
>> IND=sub2ind(size(A),2,4);
IND = 11
>> A(IND);
ans = 0.2028
>> [I,J]=ind2sub(size(A),13);
I = 1
J = 5

可以看到,sub2ind函数和ind2sub函数实现了单-双下标的转换,需要注意的是,ind2sub函数需要指定两个输出参数的接收变量,但由于MATLAB中小写字母i, j默认是用作虚数单位,因此最好是不用小写字母i, j来接收转换后的下标数字。

3.逻辑索引方式

除了这种双下标和单下标的数字索引外,MATLAB中访问数组元素,还可以通过逻辑索引的方式。通常是通过比较关系运算产生一个满足比较关系的数组元素的索引数组(实际上是一个由0,1组成的逻辑数组),然后利用这个索引数组来访问原数组,并进行重新赋值等操作。

例3-17 逻辑索引。

>> A=[0.0153 0.4186 0.8381 0.5028 0.1934;
      0.7468 0.8462 0.0196 0.7095 0.6822;
      0.4451 0.5252 0.6813 0.4289 0.3028;
      0.9318 0.2026 0.3795 0.3046 0.5417;
      0.4660 0.6721 0.8318 0.1897 0.1509];
>> B=A>0.8; %通过比较关系运算产生逻辑索引(实际上是逻辑数组)
B =
    0 0 1 0 0
    0 1 0 0 0
    0 0 0 0 0
    1 0 0 0 0
    0 0 1 0 0
>> A(B)=0; %通过逻辑索引访问原数组元素,并重新赋值
A =
   0.0153 0.4186 0 0.5028 0.1934
   0.7468 0 0.0196 0.7095 0.6822
   0.4451 0.5252 0.6813 0.4289 0.3028
        0 0.2026 0.3795 0.3046 0.5417
   0.4660 0.6721 0 0.1897 0.1509

3.5.3 数组的扩展和裁剪

在许多操作过程中,需要对数组进行扩展或裁剪。数组扩展是指在超出数组现有尺寸的位置添加新元素;裁剪是指从现有数据中提取部分,产生一个新的小尺寸的数组。

1.变量编辑器(Variable Editor)

变量编辑器是MATLAB提供的对数组进行编辑的交互式图形界面工具(详见本书的2.3节)。双击MATLAB默认界面下工作空间下的某一个变量,都能打开变量编辑器,从而进行数组元素的编辑。

变量编辑器界面类似于电子表格界面,每一个单元格就是一个数组元素。当单击超出数组当前尺寸的位置的单元格,并输入数据赋值时,实际上就是在该位置添加数组元素,即进行了数组的扩展操作,如图3-1所示。

图3-1 在变量编辑器中扩展数组

通过鼠标双击工作空间下的4行4列的数组变量A,打开了数组A的编辑器界面,然后在第6行第6列的位置单击单元格并输入数值,然后在其他位置单击鼠标或按下回车键,都可以使当前扩展操作即刻生效,如图3-1所示,数组A被扩展为6行6列的数组,原有元素不变,在第6行第6列的位置赋值为3.12,其他扩展的位置上元素被默认赋值为0。

通过变量编辑器也可以裁剪数组,这主要是对数组行、列的删除操作。需要通过鼠标右键菜单来实现。变量编辑器中单击某单元格后,单击鼠标右键,弹出如图3-2所示的菜单。

图3-2 变量编辑器右键菜单

在如图3-2所示的菜单中,选择Delete命令,就可以指定删除当前数组中选定位置元素所在的整行或者整列。Delete对话框如图3-3所示,其中有多个选项,用户可以指定删除单元格数据、删除整行、删除整列。其中常用的是删除行列的操作,多次重复执行删除行、列操作,可以实现对数组的裁剪。

图3-3 Delete对话框

图形用户界面的变量编辑器使用简单,但如果对数组的扩展或裁剪操作实际比较复杂时,通过变量编辑器实现是比较繁琐低效的。本节后面内容介绍通过MATLAB命令对数组的扩展和裁剪。

2.数组扩展的cat函数

MATLAB中可以通过cat系列函数将多个小尺寸数组按照指定的连接方式,组合成大尺寸的数组。这些函数包括:cat,horzcat和vertcat。

(1)cat函数可以按照指定的方向将多个数组连接成大尺寸数组,其基本语法格式为:

C = cat(dim, A1, A2, A3, A4, …)

dim用于指定连接方向。对于两个数组的连接,cat(1, A, B)实际上相当于[A; B],近似于把两个数组当做两个行元素连接;cat(2, A, B)实际上相当于[A, B],近似于把两个数组当做两个列元素连接。

(2)horzcat(A1, A2, …)是水平方向连接数组,相当于cat(2, A1, A2, …);vertcat(A1, A2, …)是垂直方向连接数组,相当于cat(1, A1, A2, …)。

不管哪个连接函数,都必须保证被操作的数组可以被连接,即在某个方向上尺寸一致。如horzcat函数要求被连接的所有数组都具有相同的行数,而vertcat函数要求被连接的所有数组都具有相同的列数。

例3-18 通过cat函数扩展数组。

>> A =[ 0.7468 0.4660 0.5252 0.8381 0.3795;
        0.4451 0.4186 0.2026 0.0196 0.8318;
        0.9318 0.8462 0.6721 0.6813 0.5028];
>> B=eye(3);
B =
    1 0 0
    0 1 0
    0 0 1
>> C=magic(5);
C =
   17 24 1 8 15
   23 5 7 14 16
    4 6 13 20 22
   10 12 19 21 3
   11 18 25 2 9
>> cat(1,A,B); %列数不同,不能垂直连接
??? Error using ==> cat
CAT arguments dimensions are not consistent.
>> cat(2,A,B); %行数相同,可以水平连接
ans =
0.7468 0.4660 0.5252 0.8381 0.3795 1.0000 0 0
0.4451 0.4186 0.2026 0.0196 0.8318 0 1.0000 0
0.9318 0.8462 0.6721 0.6813 0.5028 0 0 1.0000
>> cat(1,A,C); %列数相同,可以垂直连接
ans =
    0.7468 0.4660 0.5252 0.8381 0.3795
    0.4451 0.4186 0.2026 0.0196 0.8318
    0.9318 0.8462 0.6721 0.6813 0.5028
   17.0000 24.0000 1.0000 8.0000 15.0000
   23.0000 5.0000 7.0000 14.0000 16.0000
    4.0000 6.0000 13.0000 20.0000 22.0000
   10.0000 12.0000 19.0000 21.0000 3.0000
   11.0000 18.0000 25.0000 2.0000 9.0000
>> cat(2,A,C); %行数不同,不能水平连接
??? Error using ==> cat
CAT arguments dimensions are not consistent.
>> horzcat(A,B);
ans =
0.7468 0.4660 0.5252 0.8381 0.3795 1.0000 0 0
0.4451 0.4186 0.2026 0.0196 0.8318 0 1.0000 0
0.9318 0.8462 0.6721 0.6813 0.5028 0 0 1.0000
>> horzcat(A,C);
??? Error using ==> horzcat
All matrices on a row in the bracketed expression must have the
same number of rows.
>> vertzcat(A,C);
??? Undefined command/function 'vertzcat'.
>> vertcat(A,C);
ans =
     0.7468 0.4660 0.5252 0.8381 0.3795
     0.4451 0.4186 0.2026 0.0196 0.8318
     0.9318 0.8462 0.6721 0.6813 0.5028
    17.0000 24.0000 1.0000 8.0000 15.0000
    23.0000 5.0000 7.0000 14.0000 16.0000
     4.0000 6.0000 13.0000 20.0000 22.0000
    10.0000 12.0000 19.0000 21.0000 3.0000
    11.0000 18.0000 25.0000 2.0000 9.0000
3.块操作函数

MATLAB中还有通过块操作实现数组扩展的函数。

(1)数组块状复制函数repmat

repmat(A,m,n)可以将a行b列的元素A当做“单个元素”,扩展出m行n列个由此“单个元素”组成的扩展数组,实际上新产生的数组具有m*a行n*b列。

例3-19 使用块状复制函数repmat。

>> A=eye(2);
A =
    1 0
    0 1
>> repmat(A,2,2);
ans =
    1 0 1 0
    0 1 0 1
    1 0 1 0
    0 1 0 1

(2)对角块生成函数blkdiag

blkdiag(A,B,…)将数组A,B等当做“单个元素”,安排在新数组的主对角线位置,其他位置用零数组块进行填充。

例3-20 使用对角块生成函数blkdiag。

>> A=eye(2);
A =
    1 0
    0 1
>> B=ones(2,3);
B =
    1 1 1
    1 1 1
>> blkdiag(A,B);
ans =
    1 0 0 0 0
    0 1 0 0 0
    0 0 1 1 1
    0 0 1 1 1

(3)块操作函数kron

kron(X,Y)把数组Y当做一个“元素块”,先复制扩展出size(X)规模的元素块,然后每一个块元素与X的相应位置的元素值相乘。

例如,对2行3列的数组X和任意数组Y,kron(X,Y)返回的数组相当于[X(1,1)*Y X(1,2)*Y X(1,3)*Y;X(2,1)*Y X(2,2)*Y X(2,3)*Y]。

例3-21 使用块操作函数kron。

>> A=[0 1 ;1 2]; B=magic(2); C=kron(A,B);
A =
    0 1
    1 2
B =
    1 3
    4 2
C =
    0 0 1 3
    0 0 4 2
    1 3 2 6
    4 2 8 4
4.索引扩展

索引扩展是对数组进行扩展中最常用也最易用的方法。前面讲到索引寻址时,其中的数字索引有一定的范围限制,比如m行n列的数组A,要索引寻址访问一个已有元素,通过单下标索引A(a)访问就要求a<=m*n,因为A只有m*n个元素,通过双下标索引A(a,b)访问就要求a<=m,b<=n,因为A只有m行n列。

但索引扩展中使用的索引数字,就没有这些限制;相反,必然要用超出上述限制的索引数字,来指定当前数组尺寸外的一个位置,并对其进行赋值,以完成扩展操作。

通过索引扩展,一条语句只能增加一个元素,并同时在未指定的新添位置上默认赋值为0。因此,要扩展多个元素就需要组合运用多条索引扩展语句,并且经常也要通过索引寻址修改特定位置上被默认赋值为0的元素。

例3-22 索引扩展。

>> A=eye(3);
A =
    1 0 0
    0 1 0
    0 0 1
>> A(4,6)=25; %索引扩展
A =
    1 0 0 0 0 0
    0 1 0 0 0 0
    0 0 1 0 0 0
    0 0 0 0 0 25
>> A(5,2)=3; %索引扩展
A =
    1 0 0 0 0 0
    0 1 0 0 0 0
    0 0 1 0 0 0
    0 0 0 0 0 25
    0 3 0 0 0 0
>> A(5,5)=10; %索引寻址修改零元素
A =
    1 0 0 0 0 0
    0 1 0 0 0 0
    0 0 1 0 0 0
    0 0 0 0 0 25
    0 3 0 0 10 0

通过例3-22可知,组合应用索引扩展和索引寻址重新赋值命令,在数组的索引扩展中是经常会遇到的。

5.通过冒号操作符裁剪数组

相对于数组扩展这种放大操作,数组的裁剪就是产生新的子数组的缩小操作。从已知的大数据集中挑出一个子集合,作为新的操作对象,这在各种应用领域都是常见的。

MATLAB中裁剪数组,最常用的就是冒号操作符,实际上,冒号操作符实现裁剪功能时,其意义和冒号用于创建一维数组的意义是一样的,都是实现一个递变效果。

例如从100行100列的数组A中挑选偶数行偶数列的元素,相对位置不变的组成50行50列的新数组B,只需要通过B=A(2:2:100,2:2:100)就可以实现。实际上这是通过数组数字索引实现了部分数据的访问。

更一般的裁剪语法是:

B=A([a1,a2,a3, …],[b1,b2,b3, …])

表示提取数组A的a1,a2,a3,…行,b1,b2,b3,…列的元素组成子数组B。

此外,冒号还有一个特别的用法。当通过数字索引访问数组元素时,如果某一索引位置上不是用数字表示,而是用冒号代替,则表示这一索引位置可以取所有可以取到的值。

例如对5行3列的数组A,A(3,:)表示取A的第三行所有元素(从第1列到第3列),A(:,2)表示取A的第2列的所有元素(从第1行到第5行)。

例3-23 数组裁剪。

>> A=magic(8)
A =
   64 2 3 61 60 6 7 57
    9 55 54 12 13 51 50 16
   17 47 46 20 21 43 42 24
   40 26 27 37 36 30 31 33
   32 34 35 29 28 38 39 25
   41 23 22 44 45 19 18 48
   49 15 14 52 53 11 10 56
    8 58 59 5 4 62 63 1
>> A(1:2:5,3:7); %提取数组A的第1、3、5行,3到7列所有元素
ans =
    3 61 60 6 7
   46 20 21 43 42
   35 29 28 38 39
>> A(2,:); %提取数组A的第2行所有元素
ans =
    9 55 54 12 13 51 50 16
>> A(:,3:2:7); %提取数组A的第3,5,7列所有元素
ans =
    3 60 7
   54 13 50
   46 21 42
   27 36 31
   35 28 39
   22 45 18
   14 53 10
   59 4 63
>> A([3 2 1],[6 5 8]); %提取指定行列元素,注意新提取元素的顺序
ans =
   43 21 24
   51 13 16
    6 60 57
>> A(50:60); %单下标索引裁减数组,提取第50到60号元素
ans = 50 42 31 39 18 10 63 57 16 24 33
6.数组元素删除

通过部分地删除数组元素,也可以实现数组的裁剪。删除数组元素很简单,只需要对该位置元素赋值为空方括号([])即可,一般配合冒号,将数组的某些行、列元素删除。但要注意,进行删除时,索引结果必须是完整的行或完整的列,而不能是数组内部的块或单元格。

例3-24 数组元素删除。

>> A=magic(7);
A =
    30 39 48 1 10 19 28
    38 47 7 9 18 27 29
    46 6 8 17 26 35 37
     5 14 16 25 34 36 45
    13 15 24 33 42 44 4
    21 23 32 41 43 3 12
    22 31 40 49 2 11 20
>> A(1:3:8,:)=[];
A =
    38 47 7 9 18 27 29
    46 6 8 17 26 35 37
    13 15 24 33 42 44 4
    21 23 32 41 43 3 12
>> A(:,[3 5 6])=[];
A =
    38 47 9 29
    46 6 17 37
    13 15 33 4
    21 23 41 12

通过例3-24可见,数组元素的部分删除是直接在原始数组上进行的操作,在实际应用中,要考虑在数组元素删除前要不要先保存一个原始数组的副本,避免不小心造成对原始数据的破坏。

另外,单独的一次删除操作只能删除某些行或某些列,因此一般需要通过两条语句才能实现行列两个方向的数组元素删除。

3.5.4 数组形状的改变

MATLAB中有大量内部函数可以对数组进行改变形状的操作,包括数组转置,数组平移和旋转,以及数组尺寸的重新调整。

1.数组转置

MATLAB中进行数组转置最简单的是通过转置操作符(')。需要注意的是:

(1)对于有复数元素的数组,转置操作符(')在变换数组形状的同时,也会将复数元素转化为其共轭复数。

(2)如果要对复数数组进行非共轭转置,可以通过点转置操作符(.')实现。

共轭和非共轭转置也可以通过MATLAB函数完成,transpose实现非共轭转置,功能等同于点转置操作符(.');ctranspose实现共轭转置,功能等同于转置操作符(')。当然,这4种方法对于实数数组转置结果是一样的。

例3-25 数组转置。

>> A =[0.9501 0.6068 0.8913 0.4565;
       0.2311 0.4860 0.7621 0.0185];
>> A';
ans =
    0.9501 0.2311
    0.6068 0.4860
    0.8913 0.7621
    0.4565 0.0185
>> B =[2-i,3+4i,2,5i;6+i,4-i,2i,7];
B =
   2.0000 - 1.0000i 3.0000 + 4.0000i 2.0000 0 + 5.0000i
   6.0000 + 1.0000i 4.0000 - 1.0000i 0 + 2.0000i 7.0000
>> B';
ans =
   2.0000 + 1.0000i 6.0000 - 1.0000i
   3.0000 - 4.0000i 4.0000 + 1.0000i
   2.0000 0 - 2.0000i
       0 - 5.0000i 7.0000
>> ctranspose(B);
ans =
   2.0000 + 1.0000i 6.0000 - 1.0000i
   3.0000 - 4.0000i 4.0000 + 1.0000i
   2.0000 0 - 2.0000i
       0 - 5.0000i 7.0000
>> B.';
ans =
   2.0000 - 1.0000i 6.0000 + 1.0000i
   3.0000 + 4.0000i 4.0000 - 1.0000i
   2.0000 0 + 2.0000i
       0 + 5.0000i 7.0000
>> transpose(B);
ans =
   2.0000 - 1.0000i 6.0000 + 1.0000i
   3.0000 + 4.0000i 4.0000 - 1.0000i
   2.0000 0 + 2.0000i
        0 + 5.0000i 7.0000

在实际使用中,由于操作符的简便性,经常会使用操作符而不是转置函数来实现转置。但在复杂的嵌套运算中,转置函数可能是唯一的可用方法,所以,两类转置方式都要掌握。

2.数组翻转

MATLAB中数组翻转的函数如表3-2所示。

表3-2 数组翻转函数

例3-26 数组翻转。

>> A =[0.8214 0.9218 0.9355;
      0.4447 0.7382 0.9169];
>> flipud(A); %上下翻转
ans =
   0.4447 0.7382 0.9169
   0.8214 0.9218 0.9355
>> fliplr(A);
ans =
   0.9355 0.9218 0.8214
   0.9169 0.7382 0.4447
>> flipdim(A,1);
ans =
   0.4447 0.7382 0.9169
   0.8214 0.9218 0.9355
>> rot90(A);
ans =
   0.9355 0.9169
   0.9218 0.7382
   0.8214 0.4447
>> rot90(A,2);
ans =
   0.9169 0.7382 0.4447
   0.9355 0.9218 0.8214
3.数组尺寸调整

改变数组形状,还有一个常用的函数是reshape,它可以把已知数组改变成指定的行列尺寸。

对于m行n列的数组A,B=reshape(A,a,b)可以将其调整为a行b列的尺寸,并赋值给变量B,这里必须满足m*n=a*b,在尺寸调整前后,两个数组的单下标索引不变,即A(x)必然等于B(x),只要x是符合取值范围要求的单下标数字。也就是说,按照列优先原则把A和B的元素排成一列,那结果必然是一样的。

例3-27 数组尺寸调整。

>> A =[0.4451 0.4186 0.2026 0.0196;
       0.9318 0.8462 0.6721 0.6813;
       0.4660 0.5252 0.8381 0.3795];
>> reshape(A,2,6);
ans =
   0.4451 0.4660 0.8462 0.2026 0.8381 0.6813
   0.9318 0.4186 0.5252 0.6721 0.0196 0.3795
>> reshape(A,6,2);
ans =
   0.4451 0.2026
   0.9318 0.6721
   0.4660 0.8381
   0.4186 0.0196
   0.8462 0.6813
   0.5252 0.3795
>> reshape(A,8,2); %a*b不等于m*n时会报错
??? Error using ==> reshape
To RESHAPE the number of elements must not change.

3.5.5 数组运算

本节介绍数组的各种数学运算。

1.数组-数组运算

最基本的就是数组和数组的加(+)、减(-)、乘(*)、乘方(^)等运算。要注意,数组的加、减,要求参与运算的两个数组具有相同的尺寸,而数组的乘法要求第一个数组的列数等于第二个数组的行数,乘方运算在指数n为自然数时相当于n次自乘,这要求数组具有相同的行数和列数。

关于指数为其他情况的乘方,本节不作讨论,读者可以参考有关高等代数书籍。

例3-28 使用数组-数组运算。

>> A=magic(4);
A =
   16 2 3 13
    5 11 10 8
    9 7 6 12
    4 14 15 1
>> B=eye(4);
B =
   1 0 0 0
   0 1 0 0
   0 0 1 0
   0 0 0 1
>> C=ones(4,2);
C =
   1 1
   1 1
   1 1
   1 1
>> A+B;
ans =
   17 2 3 13
    5 12 10 8
    9 7 7 12
    4 14 15 2
>> B-A;
ans =
   -15 -2 -3 -13
    -5 -10 -10 -8
    -9 -7 -5 -12
    -4 -14 -15 0
>> A*C;
ans =
   34 34
   34 34
   34 34
   34 34
>> C*C';
ans =
    2 2 2 2
    2 2 2 2
    2 2 2 2
    2 2 2 2
>> (C*C')^3;
ans =
   128 128 128 128
   128 128 128 128
   128 128 128 128
   128 128 128 128

数组除法实际上是乘法的逆运算,相当于参与运算的一个数组和另一个数组的逆(或伪逆)数组相乘。MATLAB中数组除法有左除(/)和右除(\)两种。

(1)A/B相当于A*inv(B)或A*pinv(B)。

(2)A\B相当于inv(A)*B或pinv(A)*B。

其中,inv是数组求逆函数,仅适用于行列数相同的方形数组(在线性代数中,称为方阵);pinv是求数组广义逆的函数。关于逆矩阵和广义逆矩阵的知识,请读者参考有关的高等代数的书籍。

例3-29 使用数组除法。

>> A=[3 5 6;2 1 4;2 5 6];
>> B =[-0.4326 0.2877 1.1892;
       -1.6656 -1.1465 -0.0376;
        0.1253 1.1909 0.3273];
>> A/B;
ans =
   4.9369 -3.0803 0.0406
   3.9586 -2.4124 -2.4389
   4.7620 -2.3806 0.7564
>> A*inv(B);
ans =
   4.9369 -3.0803 0.0406
   3.9586 -2.4124 -2.4389
   4.7620 -2.3806 0.7564
>> A\B;
ans =
  -0.5579 -0.9032 0.8619
   0.5902 0.5735 0.3559
  -0.2850 0.0216 -0.5293
>> pinv(A)*B;
ans =
  -0.5579 -0.9032 0.8619
   0.5902 0.5735 0.3559
  -0.2850 0.0216 -0.5293
2.点运算

前面讲到的数组乘、除、乘方运算,都是专门针对数组定义的运算。在有些情况下,用户可能希望对两个尺寸相同的数组进行元素对元素的乘、除,或者对数组的逐个元素进行乘方,这可以通过点运算实现。

A.*B,就可以实现两个同样尺寸的数组A和数组B对应元素的乘法,同样的,A./B或A.\B实现元素对元素的除法,A.^n实现对逐个元素的乘方。

例3-30 使用点运算。

>> A=magic(4);
A =
   16 2 3 13
    5 11 10 8
    9 7 6 12
    4 14 15 1
>> B=ones(4)+4*eye(4);
B =
    5 1 1 1
    1 5 1 1
    1 1 5 1
    1 1 1 5
>> A.*B;
ans =
   80 2 3 13
    5 55 10 8
    9 7 30 12
    4 14 15 5
>> B.*A; %对应元素的乘法,因此和A.*B结果一样
ans =
   80 2 3 13
    5 55 10 8
    9 7 30 12
    4 14 15 5
>> B.^3;
ans =
  125 1 1 1
    1 125 1 1
    1 1 125 1
    1 1 1 125
>> A.\B; %以A的各个元素为分母,B的各个元素为分子,逐个元素作除法
ans =
   0.3125 0.5000 0.3333 0.0769
   0.2000 0.4545 0.1000 0.1250
   0.1111 0.1429 0.8333 0.0833
   0.2500 0.0714 0.0667 5.0000
>> A./B ; %以A的各个元素为分子,B的各个元素为分母,逐个元素作除法
ans =
  3.2000 2.0000 3.0000 13.0000
  5.0000 2.2000 10.0000 8.0000
  9.0000 7.0000 1.2000 12.0000
  4.0000 14.0000 15.0000 0.2000

特别要强调的是,许多MATLAB内置的运算函数,如sqrt、exp、log、sin、cos等,都只能对数组进行逐个元素的相应运算。至于专门的数组的开方、指数等运算,都有专门的数组运算函数。

3.专门针对数组的运算函数

MATLAB中,专门针对数组的运算函数一般末尾都以m结尾(m代表matirx),如sqrtm、expm、logm等,这些运算都是特别定义的数组运算,不同于针对单个数值的常规数学运算。这几个函数都要求参与运算的数组是行数和列数相等的方形数组。具体的运算方法请参考高等代数方面的书籍。

例3-31 使用数组运算函数。

>> A=magic(4);
A =
   16 2 3 13
    5 11 10 8
    9 7 6 12
    4 14 15 1
>> sqrt(A);
ans =
    4.0000 1.4142 1.7321 3.6056
    2.2361 3.3166 3.1623 2.8284
    3.0000 2.6458 2.4495 3.4641
    2.0000 3.7417 3.8730 1.0000
>> sqrtm(A);
ans =
    3.7584 - 0.2071i -0.2271 + 0.4886i 0.3887 + 0.7700i 1.9110 - 1.0514i
    0.2745 - 0.0130i 2.3243 + 0.0306i 2.0076 + 0.0483i 1.2246 - 0.0659i
    1.3918 - 0.2331i 1.5060 + 0.5498i 1.4884 + 0.8666i 1.4447 - 1.1833i
    0.4063 + 0.4533i 2.2277 - 1.0691i 1.9463 - 1.6848i 1.2506 + 2.3006i
>> exp(A);
ans =
  1.0e+006 *
    8.8861 0.0000 0.0000 0.4424
    0.0001 0.0599 0.0220 0.0030
    0.0081 0.0011 0.0004 0.1628
    0.0001 1.2026 3.2690 0.0000
>> expm(A);
ans =
  1.0e+014 *
    1.4587 1.4587 1.4587 1.4587
    1.4587 1.4587 1.4587 1.4587
    1.4587 1.4587 1.4587 1.4587
    1.4587 1.4587 1.4587 1.4587

3.5.6 数组查找

MATLAB中数组查找只有一个函数find,它能够查找数组中的非零元素并返回其下标索引。find配合各种关系运算和逻辑运算,能够实现很多查找功能。

find函数有两种语法形式:

(1)a=find(A)返回数组A中非零元素的单下标索引。

(2)[a,b]=find(A)返回数组A中非零元素的双下标索引方式。

在实际应用中,经常通过多重逻辑嵌套产生逻辑数组,判断数组元素是否符合某种比较关系,然后用find函数查找这个逻辑数组中的非零元素,返回符合比较关系的元素的索引,从而实现元素访问。

find用于产生索引数组,过渡实现最终的索引访问,因此经常不需要直接指定find函数的返回值。

例3-32 使用数组查找函数find。

>> A =[0.6822 0.1509 0.8600 0.4966 0.6449;
        0.3028 0.6979 0.8537 0.8998 0.8180;
        0.5417 0.3784 0.5936 0.8216 0.6602];
>> A>0.3;
ans =
    1 0 1 1 1
    1 1 1 1 1
    1 1 1 1 1
>> A<0.5;
ans =
    0 1 0 1 0
    1 0 0 0 0
    0 1 0 0 0
>> (A>0.3)&(A<0.5); %逻辑嵌套产生符合多个比较关系的逻辑数组
ans =
    0 0 0 1 0
    1 0 0 0 0
    0 1 0 0 0
>> find((A>0.3)&(A<0.5)); %find逻辑数组中的非零元素,返回符合关系的元素索引
ans =
    2
    6
    1 0
>> A(find((A>0.3)&(A<0.5))); %实现元素访问
ans =
    0.3028
    0.3784
    0.4966

例3-32一步一步地示例了find的最常见用法的具体使用过程。首先通过rand函数创建了待操作的随机数组A,然后通过比较运算A>0.3和A<0.5返回分别满足某一比较关系的逻辑数组,在这些逻辑数组中,1代表该位置元素符合比较关系,0则代表不符合比较关系,然后通过逻辑运算(&)可以产生同时满足两个比较关系的逻辑数组。

find操作这个逻辑数组,返回数组中非零元素的下标索引(本例中返回单下标索引),实际上就是返回原数组中符合两个比较关系的元素的位置索引,然后利用find返回的下标索引就可以寻址访问原来数组中符合比较关系的目标元素了。

3.5.7 数组排序

数组排序也是常用的数组操作,经常用在各种数据分析和处理中,MATLAB中的排序函数是sort。

sort函数可以对数组按照升序或降序进行排列,并返回排序后的元素在原数组中的索引位置,sort函数有多种应用语法格式,都有重要的应用,如表3-3所示。

表3-3 sort函数的各种语法格式

可以看到,sort都是对单独的一行或一列元素进行排序,即使对于二维数组,也是单独对每一行每一列进行排序,因此返回的索引只是单下标形式,表征排序后元素在原来行(或列)中的位置。

例3-33 数组排序。

>> A =[0.0648, 0.9883, 0.5828, 0.4235, 0.5155, 0.334, 0.4329, 0.2259];
>> sort(A) ; %按默认的升序方式排序
ans =0.0648 0.2259 0.3340 0.4235 0.4329 0.5155 0.5828 0.9883
>> [B,I]=sort(A,'descend'); %降序排序并返回索引
B =0.9883 0.5828 0.5155 0.4329 0.4235 0.3340 0.2259 0.0648
I = 2 3 5 7 4 6 8 1
>> A(I); %通过索引也可以产生降序排序的数组
ans =0.9883 0.5828 0.5155 0.4329 0.4235 0.3340 0.2259 0.0648
>> C =[0.5798 0.6405 0.7833 0.5678 0.6029 0.3050;
        0.7604 0.2091 0.6808 0.7942 0.0503 0.8744;
        0.5298 0.3798 0.4611 0.0592 0.4154 0.0150];
>> sort(C); %对每一列进行升序排序
ans =
    0.5298 0.2091 0.4611 0.0592 0.0503 0.0150
    0.5798 0.3798 0.6808 0.5678 0.4154 0.3050
    0.7604 0.6405 0.7833 0.7942 0.6029 0.8744
>> [D,I]=sort(C,2); %指定对每一行进行升序排序,并返回排序后各元素的列号
D =
    0.3050 0.5678 0.5798 0.6029 0.6405 0.7833
    0.0503 0.2091 0.6808 0.7604 0.7942 0.8744
    0.0150 0.0592 0.3798 0.4154 0.4611 0.5298
I =
    6 4 1 5 2 3
    5 2 3 1 4 6
    6 4 2 5 3 1
>> C(I); %对二维数组不能通过sort返回的单下标索引产生排序的数组
ans =
    0.3798 0.6405 0.5798 0.2091 0.7604 0.5298
    0.2091 0.7604 0.5298 0.5798 0.6405 0.3798
    0.3798 0.6405 0.7604 0.2091 0.5298 0.5798

通过例3-33可知,数组排序函数sort返回的索引,是表示了在排序方向上排序后元素在原数组中的位置,对于一维数组,这就是其单下标索引,但对二维数组,这只是双下标索引中的一个分量,因此不能简单地通过这个返回的索引值寻址产生排序的二维数组。

当然,利用这个索引结果,通过复杂一点的方法也可以得到排序数组,如例3-33中,就可以通过D=[C(1,I(1,:)); C(2,I(2,:)); C(2,I(2,:))]来产生排序数组,这种索引访问,一般只用在对部分数据的处理上。

3.6 小结

数组是MATLAB中各种变量存储和运算的通用数据结构。本章从对MATLAB中的数组进行分类概述入手,重点讲述了数组的创建、数组的属性和多种数组操作方法,这些内容是学习MATLAB必须熟练掌握的。对这些基本函数的深入的理解和熟练的组合应用,会大大提高使用MATLAB的效率,因此,读者对本章中的所有函数都要仔细体会,熟练掌握。