第三阶段学习开始咯!字符串数组(Character String Array)、元胞数组(Cell array)、构架数组(Structure array)。
MATLAB采用了面向对象编程技术,内建数据类型5种以上,还有许多专门设计的类(如符号类、内联函数类、控制工具包中的线性时不变模型类、神经网络类等)。
串数组及其相应操作,为MATLAB文字表达、复杂字符的组织、数据的可视化以及MATLAB的宏定义提供了有力的支持。
【eg.1】字符串入门
>> a=12345.6789 %给变量a赋数值标量
>> class(a) %a类别判断
>> a_s=size(a) %数值数组a的大小
>> b='S' %给变量b赋字符标量(即单个字符)
>> class(b) %b类别判断
>> b_s=size(b) %符号数组b的大小
>> whos %观察变量a,b在内存中所占字节
【eg.2】字符串的属性和标识
>> a='This is an example.'
>> size(a)
>> a14=a(1:4) %提出一个字符串
>> ra=a(end:-1:1) %字符串倒排
>> ascii_a=double(a) %产生ASCII码
>> char(ascii_a) %把ASCII码转换成字符串
>> %使字符串中字母全部大写
>> w=find(a>='a' & a<='z'); %找出字符串中小写字母的元素位置
>> ascii_a(w)=ascii_a(w)-32; %大小写字母ASCII值差32.用数值加法改变部分码值
>> char(ascii_a) %把更新后的ASCII码翻成字符
>> A='这是一个算例.'; %创建中文字符串
>> A_s=size(A) %串数组的大小
>> A56=A([5 6]) %取串的子数组
>> ASCII_A=double(A) %获取ASCII码
>> char(ASCII_A) %把ASCII码翻译成字符
>> b='Example"3.1.2-1"'
【eg.3】复杂串数组的创建
>> S=['This string array'
'has multiple rows'] %多行串数组的直接输入
>> size(S)
>> S1=char('This string array','has two rows.')
>> S2=str2mat('这','字符','串数组','','由4行组成') %“空串”会产生空格行
>> S3=strvcat('这','字符','串数组','','由4行组成') %“空串”不会产生一个空格行
>> size(S3)
【eg.4】int2str(把整数数组转换成串数组)、num2str(非整数转换串数组)、mat2str(常与eval指令配用,把数值数组换换成输入形态的串数组)
>> A=eye(2,4) %生成一个(2*4)数值数组
>> A_str1=int2str(A) %转换成(2*10)串数组,
>> size(A_str1)
>> rand('state',0)
>> B=rand(2,4); %生成数值矩阵
>> B3=num2str(B,3) %保持3位有效数字,转换成串
>> B_str=mat2str(B,4) %保持4位有效数字,转换成“数组输入形式”串
>> Expression=['exp(-',B_str,')'];
>> eval(Expression)
>> a=2; %衰减系数
w=3; %设置震荡频率
t=0:0.01:10; %取自变量采样数组
y=exp(-a*t).*sin(w*t); %计算函数值,产生函数数组
[y_max,i_max]=max(y); %找最大值元素位置
t_text=['t=',num2str(t(i_max))]; %生成最大值点的横坐标字符串
y_text=['y=',num2str(y_max)]; %生成最大值点的纵坐标字符串
>> max_text=char('maximum',t_text,y_text); %生成标志最大值点的字符串
>> %生成标志图名用的字符串
>> tit=['y=exp(-',num2str(a),'t)*sin(',num2str(w),'t)'];
>> plot(t,zeros(size(t)),'k') %画纵坐标为0的基准线
>> hold on %保持绘制的先不被清除
>> plot(t,y,'b') %用蓝色画y(t)曲线
>> plot(t(i_max),y_max,'r.','MarkerSize',20) %用大红点标最大值点
>> text(t(i_max)+0.3,y_max+0.05,max_text) %用大红点标最大值点
>> title(tit),xlabel('t'),ylabel('y'),hold off %书写图名、横坐标名、纵坐标名
【eg.6】利用
元胞数组(Cell Array)创建复杂字符串
a='MATLAB R2015b';
b='includes new data types:'; %创建单行字符串a,b
c1='Multidimensional array';
c2='User-definable data structure';
c3='Cell arrays';
c4='Character array';
c5='Function handle';
c=char(c1,c2,c3,c4,c5); %创建多行字符串c
C={a;b;c}; %利用元胞数组存放长短不同的字符内容
disp([C{1:2}]) %显示前两个元胞中的字符内容
disp('') %显示一行空白
disp(C{3}) %显示第三个元胞中的字符内容
指令 | 含义 | 指令 | 含义 |
abs | 把串翻译成ASCII码 | hex2dec | 十六进制串-->十进制整数 |
base2dec | 任意进制串-->十进制整数 | dex2num | 十六进制串-->浮点数 |
bin2dec | 二进制串->十进制整数 | int2str | 整数-->串 |
char | 任何类型-->串 | mat2str | 数值矩阵-->eval可调用的格式 |
dec2base | 十进制整数-->任意进制串 | num2str | 数值-->串 |
dec2bin | 十进制整数-->二进制串 | setstr | ASCII码-->串 |
dec2hex | 十进制整数-->十六进制串 | sprintf | 数值-->串(控制格式) |
double | 任何-->双精度数值 | sscanf | 串-->数(控制格式) |
fprintf | 把格式化数据写到文件或屏幕 | str2num | 串-->数值 |
与num2str、mat2str相比:fprintf、sprintf的转换格式更灵活。
rand('state',0);
a=rand(2,2); %产生(2*2)随机库
s1=num2str(a) %数值数组-->串
s_s=sprintf('%.10e\n',a) %10数位科学记述串,每写一个元素就换行
fprintf('%.5g\\',a) %以5位数位最短形式显示,不能赋值用
s_sscan=sscanf(s_s,'%f',[3,2]) %浮点格式把串转换成(3*2)数值数组
blanks(n) :创建n个空格串、
char(s1,s2,...):把串s1、s2等逐个写成行,形成多行数组、
deblank(s):删去串尾部的空格符
eval(s):把串s当做MATLAB指令运行
eval(s1,sc):把串s1当做MATLAB指令运行,若s1运行发生错误,则运行sc
feval(f,x,y,...):对输入量x,y等计算函数f
findstr(s1,s2):在长串中找短串的起始字符的下标
ischar(s):s是字符串,则判“真”给出逻辑1
isletter(s):以逻辑1指示s里文字符的位置
isspace(s):以逻辑1指示s里空格符的位置
lasterr:发出的最新错误信息
lower(s):使串s里的英文字母全部小写
str2mat(s1,s2,...):把串s1、s2等逐个写成行,形成多行数组
strcat(s1,s2,...):把串s1、s2等连接成长串
strcmp(s1,s2):若串s1、s2相同,判断“真”给出逻辑1
strjust(s):字符串的对齐方式:右对齐/左对齐/对中
strmatch(s1,s2):逐行搜索串s2,给出以s1开头的那些行的行号
strncmp(s1,s2,n):若串s1、s2的前n个字符相同,则判断“真”给出逻辑1
strrep(s1,s2,s3):串s1中所有给出s2的地方替换成s3
strtok(s):找出第一个间隔符前的内容
strvcat(s1,s2,...):把 串s1、s2等逐个写成行,形成多行数组,并删除全空行
upper(s):使s里的英文字母全部大写
(1)元胞数组(Cell array)如同银行保险箱库,该数组基本组分(Element)是元胞(Cell)。每个元胞自身在数组中是平等的,只能以下标区分。
(2)元胞可以存放任何类型、任何大小的数组(任意维数数值数组、字符串数组、符号对象等),同一个元胞数组中各元胞中的内容可以不同。
(3)元胞数组对元胞编制方法:单下标编址&全下标编址。
单下标编址:第一行第一列第一页的元胞序号1,沿列而下,直到第一列的元胞全部编完;接下来,沿第二列而下;以此类推,直到第一页编完,直至第二页沿第一列而下...
全下标编址:编址中的序号1为行号;序号2为列号;序号3为页号。
【eg】元胞标识寻访&内容编址寻访
数值数组/字符串数组:同一数组各元素的数据类型相同。
元胞数组:元胞&元胞里的内容不同。两种寻访操作:元胞外标识(Cell Indexing)&元胞内编址(Content addressing)。“外标识的元胞元素”用“圆括号()”。“编址元胞元素内涵”用“花括号{}”。
eg:二维元胞数组A:
A(2,3):A元胞数组中第2行第3列元胞元素;
A{2,3}:A元胞数组第2行第3列元胞中所允许存或取的内容。
C_str=char('这是','元胞数组创建算例1'); %产生字符串
R=reshape(1:9,3,3); %产生(3*3)实数阵R
Cn=[1+2i]; %产生复数标量
S_sym=sym('sin(-3*t)*exp(-t)'); %产生符号函数量
%直接创建法一:外标识元胞元素赋值法
A(1,1)={C_str};
A(1,2)={R};
A(2,1)={Cn};
A(2,2)={S_sym};
A %显示元胞数组
%直接创建方法二:编址元胞元素内涵的直接赋值法
B{1,1}=C_str;
B{1,2}=R;
B{2,1}=Cn;
B{2,2}=S_sym;
celldisp(B) %显示元胞数组内容
【eg】元胞数组的扩充、收缩、重组
利用cell指令:创建元胞数组;
指令cellplot:能用图形形象化表示元胞数组的内容,第二个输入量是用于显示色彩图例。用大白格:表示元胞;小方格:表示所存数组;色彩:表示数据属性。
C=cell(2);
C(:,1)={char('Another','text string');10:-1:1} %对第一列元胞赋值
AC=[A C] %空格(或逗号)利用来分隔列
A_C=[A;C] %分号利用来分隔行
>> cellplot(A_C,'legend') %cellplot能用图形形象化表示:元胞数组的内容
>> A_C(3,:)=[] %删除第3行,使得A_C成为(3*2)元胞数组
>> R_A_C=reshape(A_C,2,3)
【eg】元胞数组内容的调取
%调取一个元胞
>> f1=R_A_C(1,3) %使用圆括号寻访得到元胞,不仅是内容
>> class(f1)
%调取一个元胞的内容
>> f2=R_A_C{1,3} %用花括号寻访内容
>> class(f2)
%调取元胞内的子数组
>> f3=R_A_C{1,1}(:,[1 2 5 6]) %注意3种括号的不同用途
%同时调取多个元胞内容
>> [f4,f5,f6]=deal(R_A_C{[1,3,4]}) %取3个元胞内容,赋值给3个变量
【eg】num2cell函数:把数值数组-->元胞数组
rand('state',0);
A=rand(2,3,2) %生成(2*3*2)数值数组A
C1=num2cell(A) %把数值数组A转换成维数大小相同的元胞数组C1
C2=num2cell(A,1) %把“行”方向元素装入C2的一个元胞
C3=num2cell(A,[2,3]) %把“列、页”方向元素装入C3的一个元胞
【eg】mat2cell:把矩阵分解-->元胞数组、cell2mat:把元胞数组-->矩阵
x=zeros(4,5);
x(:)=1:20 %向数组x赋值
C4=mat2cell(x,[2,2],[3,2]) %把数组x转移到(2*2)元胞数组C4
%数组x的分块方式:
%(1)行维方向分成两块:第一块占2行,第二块占2行;
%(2)列维方向分成两块:第一块占3列,第二块占2列
celldisp(C4)
D=cell2mat(C4(1,:)) %C4的一个行子元胞数组转换成单个矩阵
(1)与元胞数组一样,架构数组(Structure array)也能在一个数组里存放各类数据,架构数组组织数据能力更强、更富变化。
(2)架构数组基本组分(Element)是架构(Structure),架构必须在划分“域”后才能使用。数据不能直接存放于架构,只能存放于域中。
(3)架构的域(Field),可以存放任何类型、任意大小的数组。
(4)架构数组对架构的编址方法:单下标编址&全下标地址。
元胞数组 | 架构数组 | |
举例 | (3*4)元胞数组A | (3*4)架构数组B,名为f1、f2两个域 |
基本组分(Element) | 元胞 | 架构 |
对基本组分的编址 | 全下标&单下标:A(1,2),A(4) | 全下标&单下标:B(1,2)、B(4) |
可存放的数据类型 | 任何类型 | 任何类型 |
直接存放数据的场所 | 元胞本身:元胞A(1,2) | 域:架构域B(1,2).f1 |
基本组分的寻访方式 | 被标识的元胞名:A(1,2) |
被标识的架构名:B(1,2) |
具体内容的寻访方式 | “花括号{}”标识的元胞名:A{1,2} | “带域名”标识架构名:B(1,2).f1 |
元胞数组 <-->架构数组 | cell2struct:元胞数组-->架构数组 | struct2cell:架构数组--> 元胞数组 |
>> g_h.name='一号房子'; %架构的域=(架构名).(域名)标识
g_h.volume='2000立方米';
g_h.parameter.temperature=[31.2 30.4 31.6 28.7
29.7 31.1 30.9 29.6]
g_h.parameter.humidity=[62.1 59.5 57.7 61.5 62.0 61.9 59.2 57.5]
g_h %显示单架构结构内容
g_h.parameter
g_h.parameter.temperature
g_h(2,3).name='六号房'; %产生(2*3)架构数组
g_h %显示架构数组的结构:行列数+域
g_h(2,3) %显示元素架构的结构:域;是否有子域
【eg】利用构造函数struct创建架构数组
struct指令不能直接创建带子域的架构数组,子域需要另行创建。
a=cell(2,3); %创建(2*3)空元胞数组
g_h_1=struct('name',a,'volume',a,'parameter',a(1,2))
g_h_2=struct('name',a,'volumn',[],'parameter',[])
g_h_3(2,3)=struct('name',[],'volumn',[],'parameter',[])
a1={'六号房'};a2={'3200立方米'};
g_h_4(2,3)=struct('name',a1,'volumn',a2,'parameter',[]);
T6=[31.2 30.4 31.6 28.7 29.7 31.1 30.9 29.6];
g_h_4(2,3).parameter.temperature=T6;
g_h_4
调取&设置架构数组中的数据:fieldnames指令:查询域名、子域名(得到的fieldnames的类型是)。getfield、setfield指令:调取&设置架构域中的数据内容。
【说明】
(1)函数tf(num,den)中,输入量num是有理分式矩阵的“分子多项式系数矩阵”,den是有理分式矩阵的“分母多项式系数矩阵”。
(2)getfield(SSTF,'den',{2,1})的等价指令形式:SSTF.den(2,1)、getfield(SSTF.den(2,1))、getfield(SSTF,FN{2},{2,1})。
(3)SSTF=setfield(SSTF,'num',{2,1},{[1 3 1]})的等价指令:SSTF.num{2,1}=[1 3 1]、SSTF.num(2,1)={[1 3 1]}、SSTF=setfield(SSTF,FN(1),{2,1},{[0 1 3 1]})等。
【eg】调取&设置架构数组中的数据
Stf=tf({3,2;[4,1],1},{[1,3,2],[1,1,1];[1,2,2,1],[1,0]})
SSTF=struct(Stf) %把对象转换成架构,并显示架构的组成
FN=fieldnames(SSTF) %获得域名元胞数组FN
class(FN) %检查FN的类别
FC=getfield(SSTF,'den',{2,1}) %相当于FC=SSTF.den(2,1)
FC{1}
poly2str(FC{1},'s')
SSTF.num{2,1} %显示被重新设置后的情况
SSTF=setfield(SSTF,'num',{2,1},{[1 3 1]}) %注意花括号的使用
SSTF.num{2,1} %显示被重新设置后的情况
【eg】架构数组的扩充&收缩
size(SSTF) %原架构是一个“单构架”
SSTF(2,2)=struct(tf(1,[1 1])) %把1/(s+1)放在第2行第2列构架中
size(SSTF)
SSTF(1,:)=[] %收缩成为(1*2)构架
S22n=SSTF(1,2).num,S22d=SSTF(1,2).den %取出第2架构num域和den域
printsys(S22n{1},S22d{1}) %显示成习惯的表达形式
【eg】添加&删除域
clear,for k=1:10;department(k).number=['No.',int2str(k)];end %创建架构数组
department
department(1).teacher=40;department(1).student=300;
department(1).PC_computer=40;
department
department(2).teacher.male=35;department(2).teacher.female=13;
D2T=department(2).teacher
D1T=department(1).teacher
department(2).teacher=rmfield(department(2).teacher,'male');
department(2).teacher
department=rmfield(department,'student') %删除一个域
department=rmfield(department,{'teacher';'PC_computer'}) %删除2个域
n_ex=5;
for k=1:n_ex,ex(k).f=(k-1)*n_ex+[1:5];end %创建(1*5)架构数组
ex %显示构架数组的结构
disp([blanks(10),'架构域中 '])
for k=1:n_ex,dis(ex(k).f),end
【eg】数值运算操作&函数对架构数组的应用
n_ex=5; %架构数组的长度
for k=1:n_ex,ex(k).f=(k-1)*n_ex+[1:5];end %创建(1*5)架构数组
ex %显示构架数组的结构
disp([blanks(10),'架构域中 ']) %显示架构数组的域中内容
for k=1:n_ex,disp(ex(k).f),end
class(ex(1).f) %检查域中内容的类型
sum_f=zeros(1,5); %对各架构域中数值数组相应位置的数据相加求和
for k=1:n_ex,sum_f=sum_f+ex(k).f;end,sum_f %对架构数组域中各元素分别求平方根
disp([blanks(20),'ex,f的平方根值'])
for k=1:n_ex,disp(sqrt(ex(k).f)),end
由于架构数组&元胞数组一样,具有存放各种类型数据的能力,因此这两种类型的数组之间可以相互交换。转换指令:struct2cell、cell2struct。
(1)struct2cell指令:架构数组的“域”转换为元胞数组的“行”。而元胞数组的第二、三等维分别是原架构数组的第一、二维。原架构数组中的子域,将仍被当做子域架构存放到新的元胞数组中。
(2)cell2struct指令:把元胞数组-->架构数组之前,选择“哪一维”-->“域”。在抉择确定后,给出域名字符串。
【eg】转换指令struct2cell、cell2struct的使用
%创建“带两个域的(1*5)架构数组
for k=1:5,ex(k).s=['No.',int2str(k)];ex(k).f=(k-1)*5+[1:5];end
%显示架构数组的内容
fprintf('%s\n','ex.s域的内容');fprintf('%s\n',blanks(4))
for k=1:5;fprintf('%s\n',[ex(k).s blanks(1)]);end
fprintf('%s\n',blanks(1)),fprintf('%s\b','ex.f域的内容')
for k=1:5;disp(ex(k).f);end
clc
C_ex=struct2cell(ex); %带2个域的架构数组-->(2*1*5)元胞数组
size(C_ex)
fprintf('%s\t',[C_ex{1,1,1},blanks(3)]) %显示C_ex第1页第1行第1列内容
fprintf('%5g\t',C_ex{2,1,1}) %显示C_ex第2页第1行第1列的内容
clc
%把元胞数组转换为架构数组之一
%选定C_ex“第一维'页'”转换为域,维度为2,因此取两个域名S_char、F_num。
FS={'S_char';'F_num'}; %用元胞数组预建域名字符串
EX1=cell2struct(C_ex,FS,1) %元胞数组-->构架数组
EX1(1) %观察新架构EX1第1构架的情况
clc
%把元胞数组转换为架构数组之二
%选定C_ex的“第2维”转换为域,由于第2维长度为1,取一个域名xxEX2=cell2struct(C_ex,'xx',2)
%把元胞数组转换为架构数组之三
%选定C_ex的“第3维”转换为域。由于第3维长度为5,取5个域名:y1,y2,y3,y4,y5YY=strvcat('y1','y2','y3','y4','y5');EX3=cell2struct(C_ex,YY,3)EX3(1) %观察第1架构的情况EX3(2) %观察第2架构的情况
【eg】带子域的架构数组-->元胞数组
>> %带子域的架构数组-->元胞数组
ex(1,1).s %原架构ex(1,1).s中的内容
%增设子域,并把ex架构数组扩充为(3*5)
ex(3,1).s.num=1/3;
ex(1,1).s %原架构ex(1,1).s中的内容
ex(3,1).s %经新赋值后,架构ex(3,1).s中的内容-
C_ex_sub=struct2cell(ex) %架构-->元胞数组
size(C_ex_sub) %观察新元胞数组的大小
C_ex_sub{1,1,1} %观察第1元胞中的内容
C_ex_sub{1,3,1} %观察(1,3,1)元胞中的内容
图20 带子域的架构数组-->元胞数组
第三阶段至此结束!学习了字符串&元胞&构架数组!
撒花!(*^__^*)