1. 程式人生 > >關於MATLAB中結構陣列的使用

關於MATLAB中結構陣列的使用

轉載出處: 

結構(struct)陣列

要在MALTAB中實現比較複雜的程式設計,就不能不用struct型別。而且在MATLAB中實現struct比C中更為方便。

4. 3.1 結構陣列的建立
MATLAB提供了兩種定義結構的方式:直接應用和使用struct函式。
1. 使用直接引用方式定義結構
與建立數值型陣列一樣,建立新struct物件不需要事先申明,可以直接引用,而且可以動態擴充。比如建立一個複數變數x:
x.real = 0; % 建立欄位名為real,併為該欄位賦值為0
x.imag = 0 % 為x建立一個新的欄位imag,併為該欄位賦值為0 
x = 
real: 0
imag: 0 
然後可以將旗動態擴充為陣列:
x(2).real = 0; % 將x擴充為1×2的結構陣列
x(2).imag = 0; 
在任何需要的時候,也可以為陣列動態擴充欄位,如增加欄位scale:
x(1).scale = 0; 
這樣,所有x都增加了一個scale欄位,而x(1)之外的其他變數的scale欄位為空:
x(1) % 檢視結構陣列的第一個元素的各個欄位的內容 
ans = 
real: 0
imag: 0
scale: 0 
x(2) % 檢視結構陣列的第二個元素的各個欄位的內容,注意沒有賦值的欄位為空
ans = 
real: 0
imag: 0
scale: [] 
應該注意的是,x的real、imag、scale欄位不一定是單個數據元素,它們可以是任意資料型別,可以是向量、陣列、矩陣甚至是其他結構變數或元胞陣列,而且不同欄位之間其資料型別不需要相同。例如:
clear x; x.real = [1 2 3 4 5]; x.imag = ones(10,10); 

陣列中不同元素的同一欄位的資料型別也不要求一樣:
x(2).real = '123';
x(2).imag = rand(5,1); 
甚至還可以通過引用陣列欄位來定義結構資料型別的某欄位:
x(3).real = x(1); x(3).imag = 3; x(3) 
ans = 
real: [1x1 struct]
imag: 3 
下面看一個實際的例子來熟悉直接引用方式定義與顯示結構。
【例4.3.1-1】 溫室資料(包括溫室名、容量、溫度、溼度等)的建立與顯示。
(1) 直接對域賦值法產生結構變數  
green_house.name = '一號溫室'; % 建立溫室名欄位 
green_house.volume = '2000立方米'; % 建立溫室容量欄位
green_house.parameter.temperature = [31.2 30.4 31.6 28.7 % 建立溫室溫度欄位
29.7 31.1 30.9 29.6];
green_house.parameter.humidity = [62.1 59.5 57.7 61.5; % 建立溫室溼度欄位
62.0 61.9 59.2 57.5]; 
(2)顯示結構變數的內容
green_house % 顯示結構變數結構 
green_house = 
name: '一號溫室'
volume: '2000立方米'
parameter: [1x1 struct] 
green_house.parameter % 用域作用符號. 顯示指定域(parameter)中內容 
ans = 
temperature: [2x4 double]
humidity: [2x4 double] 
green_house.parameter.temperature % 顯示temperature域中的內容 
ans =
31.2000 30.4000 31.6000 28.7000
29.7000 31.1000 30.9000 29.6000 

【例4.3.1-2】在上例的基礎上,建立結構陣列用以儲存一個溫室群的資料。
green_house(2,3).name = '六號溫室'; %產生2×3結構陣列
green_house % 顯示結構陣列的結構 
green_house = 
2x3 struct array with fields:
name
volume
parameter 
green_house(2,3) % 顯示結構陣列元素的結構 
ans = 
name: '六號溫室'
volume: []
parameter: [] 

2. 使用struct函式建立結構
使用struct函式也可以建立結構,該函式產生或吧其他形式的資料轉換為結構陣列。
struct的使用格式為:
s = sturct('field1',values1,'field2',values2,…);
該函式將生成一個具有指定欄位名和相應資料的結構陣列,其包含的資料values1、valuese2等必須為具有相同維數的資料,資料的存放位置域其他結構位置一一對應的。對於struct的賦值用到了元胞陣列。陣列values1、values2等可以是元胞陣列、標量元胞單元或者單個數值。每個values的資料被賦值給相應的field欄位。
當valuesx為元胞陣列的時候,生成的結構陣列的維數與元胞陣列的維數相同。而在資料中不包含元胞的時候,得到的結構陣列的維數是1×1的。例如:
s = struct('type',{'big','little'},'color',{'blue','red'},'x',{3,4}) 
s = 
1x2 struct array with fields:
type
color

得到維數為1×2的結構陣列s,包含了type、color和x共3個欄位。這是因為在struct函式中{'big','little'}、{'blue','red'}和{3,4}都是1×2的元胞陣列,可以看到兩個資料成分分別為:
s(1,1) 
ans = 
type: 'big'
color: 'blue'
x: 3 
   s(1,2) 
ans = 
type: 'little'
color: 'red'
x: 4 
相應的,如果將struct函式寫成下面的形式:
s = struct('type',{'big';'little'},'color',{'blue';'red'},'x',{3;4}) 
s = 
2x1 struct array with fields:
type
color

則會得到一個2×1的結構陣列。
下面給出利用struct構建結構陣列的具體例項。
【例4.3.1-3】利用函式struct,建立溫室群的資料庫。
(1) struct預建立空結構陣列方法之一
a = cell(2,3); % 建立2×3的元胞陣列
green_house_1=struct('name',a,'volume',a,'parameter',a(1,2))
green_house_1 = 
2x3 struct array with fields:
name
volume
parameter 
(2)struct預建空結構陣列方法之二
green_house_2=struct('name',a,'volume',[],'parameter',[])     
green_house_2 = 
2x3 struct array with fields:
name
volume
parameter 
(3)struct預建空結構陣列方法之三
green_hopuse_3(2,3)=struct('name',[],'volume',[],'parameter',[]) 
green_hopuse_3 = 
2x3 struct array with fields:
name
volume
parameter 
(4)struct建立結構陣列方法之四
a1={'六號房'};a2={'3200立方米'};
green_house_4(2,3)=struct('name',a1,'volume',a2,'parameter',[]);
T6=[31.2,30.4,31.6,28.7;29.7,31.1,30.9,29.6];             green_house_4(2,3).parameter.temperature=T6;            
green_house_4 
ans = 
2x3 struct array with fields:
name
volume
parameter 

4. 3.2 結構陣列的操作

MATLAB

中專門用於對結構陣列的操作的函式並不多,通過 help datatypes獲取資料型別列表,可以看到其中的結構資料型別的有關的函式,主要如表4.3.1所示。
表4.3.1 結構陣列的操作函式
函式名   功能描述   函式名   功能描述
deal   把輸入處理成輸出   fieldnames   獲取結構的欄位名
getfield   獲取結構中指定欄位的值   rmfield   刪除結構的欄位(不是欄位內容)
setfield   設定結構陣列中指定的欄位的值   struct   建立結構陣列
struct2cell   結構陣列轉化成元胞陣列   isfield   判斷是否存在該欄位
isstruct   判斷某變數是否是結構型別    
下面舉一些具體的例子說明如果對結構陣列加以操作。

【例4.3.2-1】 本例目的:一,演示函式fieldnames , getfield , setfield的使用方法;二,讓讀者感受到結構陣列對應用工具包的影響;三,演示struct函式把“物件”轉換為結構的應用。本例為獲得一個演練的結構,藉助Toolbox control 工具包中的tf函式,先產生一個用傳遞函式描寫的LTI線性時不變2輸入2輸出系統 。
(1)產生2輸入2輸出系統的傳遞函式陣“物件”
Stf=tf({3,2;[4 1],1},{[1 3 2],[1 1 1];[1 2 2 1],[1 0]}) 

Transfer function from input 1 to output...
3
#1: -------------
s^2 + 3 s + 2

4 s + 1
#2: ---------------------
s^3 + 2 s^2 + 2 s + 1
Transfer function from input 2 to output...
2
#1: -----------
s^2 + s + 1
1
#2: -

(2)為本例演示,把上述的LTI物件Stf轉換為結構
SSTF=struct(Stf)       % 把物件轉換成結構,並顯示結構的組成 
SSTF = 
num: {2x2 cell}
den: {2x2 cell}
Variable: 's'
lti: [1x1 lti] 
(3)獲得結構陣列SSTF的域名
FN=fieldnames(SSTF) % 獲得域名元胞陣列FN
class(FN)     % 檢查FN的類別 
FN = 
'num'
'den'
'Variable'
'lti'
ans =
cell 
(4)獲取SSTF.den(2,1)域的內容
FC=getfield(SSTF,'den',{2,1})     % 相當於FC=SSFT.den(2,1)
FC{1}                   % 與celldisp(FC)的作用大致相當
poly2str(FC{1},'s'),         % 為了把多項式顯示成習慣的形式 
FC = 
[1x4 double]
ans =
1 2 2 1
ans =
s^3 + 2 s^2 + 2 s + 1 
(5)重新設定SSTF.num(2,1)域的內容
SSTF.num{2,1}                 % 顯示原始情況
SSTF=setfield(SSTF,'num',{2,1},{[1 3 1]}); %   注意“花括號”的使用
SSTF.num{2,1}                     % 顯示被重新設定後的情況 
ans =
0 0 4 1
ans =
1 3 1 

【例4.3.2-2】本例演示結構陣列SSTF的擴充和收縮。(本例以例4.3.2-1的執行為基礎。)
(1)原結構是一個“單結構”
size(SSTF) 
ans =
1 1 
(2)演示結構的擴充
SSTF(2,2)=struct(tf(1,[1 1]))     % 把1/(s+1)放在第2行第2列結構中
size(SSTF) 
SSTF = 
2x2 struct array with fields:
num
den
Variable
lti
ans =
2 2 
(3)演示結構陣列的收縮:刪除結構陣列的第1行
SSTF(1,Smile
=[]                   % 收縮成為 的結構
S22n=SSTF(1,2).num,S22d=SSTF(1,2).den   % 取出第2結構num域和den域的內容
printsys(S22n{1},S22d{1})           % 顯示成習慣的表達形式 
SSTF = 
1x2 struct array with fields:
num
den
Variable
lti
S22n = 
[1x2 double]
S22d = 
[1x2 double]
num/den = 
1
-----
s + 1 

【例4.3.2-3】對結構陣列進行域的增添和刪減操作。
(1)建立結構陣列
clear,for k=1:10;department(k).number=['No.',int2str(k)];end
department 
department = 
1x10 struct array with fields:
number 
(2)增添域:在陣列中任何一個結構上進行的域增添操作,其影響遍及整個結構陣列
department(1).teacher=40;department(1).student=300;
department(1).PC_computer=40;
department 
department = 
1x10 struct array with fields:
number
teacher
student
PC_computer 
(3)增添子域的操作隻影響被操作的那個具體結構,而不是影響整個結構陣列
department(2).teacher.male=35;department(2).teacher.female=13;
D2T=department(2).teacher     % 第2結構teacher域包含兩個子域
D1T=department(1).teacher     % 第1結構teacher域僅是一個數 
D2T = 
male: 35
female: 13
D1T =
40 
(4)刪除子域的操作也隻影響被操作的那個具體結構
department(2).teacher=rmfield(department(2).teacher,'male');
department(2).teacher 
ans = 
female: 13 
(5)刪除域的操作是對整個結構陣列實施的
department=rmfield(department,'student')   % 刪除一個域 
department = 
1x10 struct array with fields:
number
teacher
PC_computer 
department=rmfield(department,{'teacher';'PC_computer'})% 刪除2個域 
department = 
1x10 struct array with fields:
number 

【例4.3.2-4】數值運算操作和函式在結構域上的作用。
n_ex = 5; % 結構陣列的長度
for k = 1:n_ex,   % 建立1×5結構陣列
ex(k).f = (k-1)*n_ex + [1:5];
end;
ex                           % 顯示結構陣列的結構 
ex = 
1x5 struct array with fields:

%顯示結構陣列的域中內容
disp([blanks(10) '結構域中內容'])
for k=1:n_ex,disp(ex(k).f),end 
結構域中內容
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25 
class(ex(1).f)                   % 檢查域中內容的型別 
ans =
double 
% 對各結構域中數值陣列相應位置的資料相加求和
sum_f=zeros(1,5)
for k=1:n_ex,sum_f=sum_f+ex(k).f;end,sum_f 
sum_f =
55 60 65 70 75 
% 對結構陣列域中各元素分別求平方根
disp([blanks(20) 'ex.f的平方根值'])
for k=1:n_ex,
disp(sqrt(ex(k).f)),
end 
ex.f的平方根值
1.0000 1.4142 1.7321 2.0000 2.2361
2.4495 2.6458 2.8284 3.0000 3.1623
3.3166 3.4641 3.6056 3.7417 3.8730
4.0000 4.1231 4.2426 4.3589 4.4721
4.5826 4.6904 4.7958 4.8990 5.0000 

【例4.3.2-5】   指令struct2cell和cell2struct的使用。
(1)建立“帶2個域的 結構陣列”
for k=1:5,
ex(k).s=['No.' int2str(k)];
ex(k).f=(k-1)*5+[1:5];
end 
(2)顯示結構陣列的內容
fprintf('%s\n','ex.s域的內容 ');fprintf('%s\',blanks(4))
for k=1:5;fprintf('%s\\',[ex(k).s blanks(1)]);end
fprintf('%s\n',blanks(1)),fprintf('%s\n','ex.f域的內容 ')
for k=1:5;disp(ex(k).f);end     %顯示ex.f域內容 
ex.s域的內容 
No.1 \No.2 \No.3 \No.4 \No.5 \ 
ex.f域的內容 
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25 
(3)把ex結構陣列轉換為元胞陣列
C_ex=struct2cell(ex); % 帶2個域的(1×5)結構陣列轉換為(2×1×5)元胞陣列
size(C_ex)
fprintf('%s\',[C_ex{1,1,1},blanks(3)])   % 顯示C_ex第1頁第1行第1列內容
fprintf('%5g\',C_ex{2,1,1})         % 顯示C_ex第2頁第1行第1列內容 
ans =
2 1 5
No.1 1 2 3 4 5 
(4)把元胞陣列轉換為結構陣列之一
FS={'S_char';'F_num'};        % 用元胞陣列預建域名字串
EX1=cell2struct(C_ex,FS,1)      % 元胞陣列向結構陣列轉換 
EX1 = 
1x5 struct array with fields:
S_char
F_numric 
EX1(1)                   % 觀察新結構EX1第一結構的情況 
ans = 
S_char: 'No.1'
F_numric: [1 2 3 4 5] 

(5)把元胞陣列轉換為結構陣列之二
EX2=cell2struct(C_ex,'xx',2) 
EX2 = 
2x5 struct array with fields:
xx 
(6)把元胞陣列轉換為結構陣列之三
YY=strvcat('y1','y2','y3','y4','y5');EX3=cell2struct(C_ex,YY,3) 
EX3 = 
2x1 struct array with fields:
y1
y2
y3
y4
y5 
EX3(1)                   % 觀察第一結構情況 
ans = 
y1: 'No.1'
y2: 'No.2'
y3: 'No.3'
y4: 'No.4'
y5: 'No.5' 
EX3(2)                   % 觀察第二結構情況 
ans = 
y1: [1 2 3 4 5]
y2: [6 7 8 9 10]
y3: [11 12 13 14 15]
y4: [16 17 18 19 20]
y5: [21 22 23 24 25] 

【例4.3.2-6】   帶子域的結構陣列轉換為元胞陣列。本例中的ex結構陣列由例4.2.2-5生成,然後再執行以下程式。
ex(1,1).s                 % 原結構ex(1,1).s中的內容 
ans =
No.1 
% 增設子域,並把ex結構陣列擴充為(3×5)。
ex(1,1).s.sub='SUB 1';         % 原ex(1,1).s中的字串將因本指令而消失
ex(3,1).s.sub='SUB 3';
ex(3,1).s.num=1/3; 
ex(1,1).s                 % 經新賦值後,ex(1,1).s中的內容 
ans = 
sub: 'SUB 1' 
ex(3,1).s                 % 經新賦值後,ex(3,1).s中的內容 
ans = 
sub: 'SUB 3'
num: 0.3333 
C_ex_sub=struct2cell(ex)       % 把結構轉換為元胞陣列 
C_ex_sub(:,:,1) = 
[1x1 struct] [] [1x1 struct]
[1x5 double] [] []
C_ex_sub(:,:,2) = 
'No.2' [] []
[1x5 double] [] []
C_ex_sub(:,:,3) = 
'No.3' [] []
[1x5 double] [] []
C_ex_sub(:,:,4) = 
'No.4' [] []
[1x5 double] [] []
C_ex_sub(:,:,5) = 
'No.5' [] []
[1x5 double] [] [] 
size(C_ex_sub)             % 觀察新元胞陣列的大小 
ans =
2 3 5 
C_ex_sub{1,1,1}             % 觀察第一元胞中的內容 
ans = 
sub: 'SUB 1' 
C_ex_sub{1,3,1}             % 觀察(1,3,1)元胞中的內容 
ans = 
sub: 'SUB 3'
num: 0.3333