10/22/2006

5.4 結構陣列

5.4 Structural Array


MATLAB之第五版以上也具有結構型之資料型式,可以利用欄位名稱輸入資料庫或直接呼叫,對於以後寫資料庫之擷取型式具有相當大的方便性。而結構陣列之存在,亦可不拘資料之屬性,可為一搬文字敘述或矩陣之型式。這種結構與一般資料庫之分類法則相同,應用時相當方便。


patient
.name ‘張三豐’
.billing 3,838.00
.test [12 01 70 180
3 20 65 150
5 30 79 150]



結構陣列之型式以一個病歷作說明:在一個資料庫下有欄位名稱,若以patient為資料庫之總稱時,其下有name、billing及test等三個欄位,第一個欄位為病人之姓名,第二欄為帳單,第三欄為其檢驗之記錄;後者因每一次有相同的實驗項目,故以矩陣表示。

要建立這些資料並不困難,可在指令窗下輸入:


>>patient.name='張三豐';
>>patient.billing=3838.00;
>>patient.test=[12 01 70 180;3 20 65 150;5 30 79 150];


輸入之後,只要打入patient,即有這筆記錄:


>>patient
patient =
name: '張三豐'
billing: 3838
test: [3x4 double]


最後一項是一矩陣,它僅顯示該矩陣之大小,未顯示其內容,若要知道其內容,可以下指令:


>>patient.test
ans =
12 1 70 180
3 20 65 150
5 30 79 150


由此可見,要知道其下之欄位內容,可以在名稱與欄位名稱間加一點即可,如:


>>patient.name
ans =張三豐
>>patient.billing
ans = 3838


在其他運算式中,若要參照某一欄位內容之值時,亦可採用同樣的語法取得該值。

上面之結構仍然僅能指向某一位病人而已,若有其他病人也需同樣的結構如何表示呢?此時必須在病人之參數加上指標,以表示不同的病人利用同樣的結構建檔。如下建立第二筆記錄:


>>patient(2).name='李四文';
>>patient(2).billing=2424.00;
>>patient(2).test=[11 05 75 200;4 20 80 160;6 30 55 140];


由於patient之內容不只一個,此時若要知道此一patient的資料如何,仍然可在指令窗下指令:


>>patient
patient =
1x2 struct array with fields:
name
billing
test


但其結果出人意外的與前面不同,主要是我們已將patient變成一個1x2 的結構性矩陣,而其下之欄位名稱則會加以標明,不再標出其內容,不過若下如下之指令,則會有所要的資料:


>>patient(2)
ans =
name: '李四文'
billing: 2424
test: [3x4 double]

>>patient(1)
ans =
name: '張三豐'
billing: 3838
test: [3x4 double]

至少目前應有張三豐及李四文兩筆病人的記錄。其餘可以採用類似方法增加筆數。基本上每一新記錄均需維持相同的欄位名稱及數量,才能組成一個結構。

雖然這些資料均以結構型式存於檔案中,但如前面所述,其單獨之變數仍可以取出隨意運用,如此可以增加變數應用之彈性,例如繪出張三豐之實驗之資料:

>>bar(patient(1).test)

張三豐的病歷資料



故其內在之資料要如何處理,其情況與一般的手法相同,只是目前仍然不知道張三豐的病歷到底表示的是什麼而已。

若要瞭解這個檔案之欄位名稱,除直接打入該檔的名稱外,亦可用fieldnames這一個指令:


>>fieldnames(patient)
ans =
'name'
'billing'
'test'


其中之某欄位亦可利用rmfield這個指令去除掉:


>>patient2=rmfield(patient,'test')
patient2 =
1x2 struct array with fields:
name
billing


因此,基本結構patient2與patient相同,但少了test這個欄位。一次若要除去好幾個欄位時,則必須使用文字矩陣來處理。以往討論到矩陣時,均以數值為主,故矩陣內的項目均為數值格式,且用中括號[]作為範圍;碰到項目為文字型式時,其處理方式需以單一之文字為對象。若要採用長度不一的文字矩陣時,則各項之文字必須用撇號 ’ 號括起來,其矩陣亦必須以大括號{}作為範圍,如{'張三豐','李四文','陳五分'}是。故若要除去許多欄位時,可採用下面的方法:


>>patient2=rmfield(patient,{'test' 'billing'})
patient2 =
1x2 struct array with fields:
name


因此,patient2僅剩下name一欄了。當然欄位亦可無中生有,只要將要直接添加新欄位並設定一個值給它即可,如:


>>patient2(1).billing=20
patient2 =
1x2 struct array with fields:
name
billing


換言之,整個檔案均會增加一個欄位billing,而第二筆記錄欄位已存在,但仍為空值,因為尚有未該筆記錄之billing的內容:


>>patient2(2).billing
ans =
[]

>>patient2(1).billing
ans =
20


上述方法亦可用另一指令setfield來逹成:


>>setfield(patient2(2),'billing', 30)
ans =
name: '李四文'
billing: 30


事實上,結構化檔案亦可以利用struct指令來達成:


>>patient3=struct('name',{'陳五分','趙六錢'},'billing',{5656.00, 7878.00},'test',{[1 2],[3 4]})
patient3 =
1x2 struct array with fields:
name
billing
test

>>patient3(1)
ans =
name: '陳五分'
billing: 5656
test: [1 2]

>>patient3(2)
ans =
name: '趙六錢'
billing: 7878
test: [3 4]


上述指令之結構可能需要補充說明一下,以便發揮一指神功的效果。struct後面括號內包含的項目為各欄位及對應之值。當然這些值可能為文字,也可能為數值。基本上文字均需使用撇號 ’ 括起來。對應欄位後面應使用中括號[]括起來,裡面的項目內容若有好幾筆資料,則需用逗號分開。各筆若為矩陣,則需依矩陣的表示法輸入,並用中括號[]括起來。下面兩個例子可能給大家一些概念:


>>s = struct('greetings',{{'Hello, there','新年好,萬事如意'}},'lengths',[5 3])
s =
greetings: {'Hello, there' '新年好,萬事如意'}
lengths: [5 3]

>>s(1)
ans =
greetings: {'Hello, there' '新年好,萬事如意'}
lengths: [5 3]


顯然s內容僅有一項,但greetings內應有兩項:


>>s.greetings(1)
ans =
'Hello, there'

>>s.greetings(2)
ans =
'新年好,萬事如意'


再看看同一個例子,但稍做修改:


>>s = struct('greetings',{'Hello, there','新年好,萬事如意 '},'lengths',[5 3])
s =
1x2 struct array with fields:
greetings
lengths

>>s(1)
ans =
greetings: 'Hello, there'
lengths: [5 3]

>>s(2)
ans =
greetings: '新年好,萬事如意 '
lengths: [5 3]


此時s有兩筆記錄,且其lengths:均為 [5 3],足見不足的項目它會用同一個值補上去。
再看看它在說明中提供的例子:


>>ss = struct('type',{'big','little'},'color','red','x',{3 4})
ss =
1x2 struct array with fields:
type
color
x

>>ss(1)
ans =
type: 'big'
color: 'red'
x: 3

>>ss(2)
ans =
type: 'little'
color: 'red'
x: 4


這樣的結果會更清楚了,讀者應可從中體會其功能。下面是一個比較複雜的例子:


>>A=struct('data',{[3 4 7;8 0 1], [9 3 2; 7 6 5]}, ...
'personal',{struct('testyear',1999,'height',[163 178 172],...
'weight',[80 86 60]),struct('testyear',2000,'height',[157 168 159],...
'weight',[48 50 48])})
A =
1x2 struct array with fields:
data
personal

>>A(1)
ans =
data: [2x3 double]
personal: [1x1 struct]

>>A(1).data
ans =
3 4 7
8 0 1

>>A(1).personal
ans =
testyear: 1999
height: [163 178 172]
weight: [80 86 60]

>>A(2).personal
ans =
testyear: 2000
height: [157 168 159]
weight: [48 50 48]


其他相關指令如disp也可以看其結構:



>>disp(A)
1x2 struct array with fields:
data
personal


而函數isfield則可檢驗檔案結構內是否有某一特定欄位,如:


>>f=isfield(A,'data')
f =
1

下表為有關處理matlab結構之各函數:







dealDeal inputs to outputs.
fieldnamesGet structure field names.
isfieldReturn true if the field is in a structure array.
isstructReturn true for structures.
rmfieldRemove a structure field.
structCreate or convert to a structure array.
struct2cell Convert a structure array into a cell array.