结构数组(structure array) • 结构是包含一组记录的数据类型,记录存储在字段(Field)中 • 字段(Field)可以是任意数据类型的变量或者对象 • 结构类型的变量可以是一维的、二维的或者多维的数组: • 数组中每个元素(结构)的Field数目相同. • 数组中每个元素(结构)的Field名称相同 • 数组中每个元素(结构)的同一Field可存储不同类型、维数的数据 一、创建结构数组 二、结构的基本操作 三、结构的操作函数 一、创建结构数组 1、直接赋值创建结构数组 创建的时候,直接用结构的名称,配合操作符“.”和相应的 字段的名称完成创建,创建是直接给字段赋具体的数值 patient.name = 'John Doe'; patient.billing = 127.00; patient.test = [79, 75, 73; 180, 178, 177.5; 220, 210, 205]; patient patient = name: 'John Doe' billing: 127 test: [3x3 double] 结构数组名后使用索引( )就可以添加新的结构元素: patient(2).name = 'Ann Lane'; patient(2).billing = 28.50; patient(2).test = [68, 70, 68; 118, 118, 119; 172, 170, 169]; patient patient = 1x2 struct array with fields: name billing test 对于结构中未明确赋值的Field,自动赋值为空数组。 patient(3).name = 'New Name'; patient(3) ans = name: 'New Name' billing: [] test: [] 2、使用 struct() 函数创建结构数组 (1) s = struct 或 s = struct() 创建一个没有filed的结构标量(scalar (1-by-1) structure) >> s1 = struct() s1 = struct with no fields. >> whos Name Size s1 1x1 Bytes Class 0 struct Attributes (2) s = struct([]) 创建一个没有field的空结构数组(empty (0-by-0) structure ) >> s2 = struct([]) s2 = 0x0 struct array with no fields. >> whos Name Size s2 0x0 Bytes Class 0 struct Attributes (3) s = struct(field,value) 用指定的 field 和 value 创建只有一个field的结构数组 • 若 value 不是 cell array,则s 为结构标量( scalar structure) • 若 value 是 cell array,则 s 为结构数组( structure array) • 若 value是空 cell array {},则 s为空结构数组(empty (0-by-0) structure) field = 'f'; value = {'some text';[10, 20, 30];magic(5)}; s = struct(field,value) s= 3x1 struct array with fields: f 如何创建一个结构标量,使其 field 的内容为一个cell array? field = 'mycell'; value = {{'a','b','c'}}; s = struct(field,value) s= mycell: {'a' 'b' 'c'} (4)s = struct(field1,value1,...,fieldN,valueN) 创建一个有多个field的结构数组(structure array)。 value1,...,valueN中的所 有非标量 cell arrays的维数必须 相同。 • 若输入value中没有cell array, 或都是scalar cell arrays, 则 s为a scalar structure。 • 若输入value中有nonscalar cell arrays,则 s 与这些nonscalar cell arrays同维, scalar cell array 或其他数组会插入到s的每个元素的对应的field中。 • 若输入value中有empty cell array, {}, 则s 为 empty (0-by-0) structure. field1 field2 field3 field4 = = = = 'f1'; 'f2'; 'f3'; 'f4'; value1 value2 value3 value4 = = = = zeros(1,10); {'a', 'b'}; {pi, pi.^2}; {'fourth'}; s = struct(field1,value1,field2,value2,field3,value3,field4,value4) s= 1x2 struct array with fields: f1 f2 f3 f4 >> s(1) ans = f1: [0 0 0 0 0 0 0 0 0 0] f2: 'a' f3: 3.1416 f4: 'fourth' >> s(2) ans = f1: [0 0 0 0 0 0 0 0 0 0] f2: 'b' f3: 9.8696 f4: 'fourth' >> s = struct('a',{},'b',{},'c',{}) s= 创建有fields的空结构 (empty structure) 0x0 struct array with fields: a b c >> s(1).a = 'a' s= 空结构赋值: a: 'a' b: [] c: [] 3、用[ ]将小的结构数组合并为大的结构数组 (Concatenate Structures) struct1.a = 'first'; struct1.b = [1,2,3]; struct2.a = 'second'; struct2.b = rand(5); combined = [struct1, struct2] combined = 1x2 struct array with fields: a b new(1,1).a new(1,2).a new(2,1).a new(2,2).a = = = = 1; 2; 3; 4; new(1,1).b new(1,2).b new(2,1).b new(2,2).b larger = [combined; new] larger = 3x2 struct array with fields: a b = = = = 10; 20; 30; 40; 4、创建嵌套结构数组(Nested Structure Array) a >> a.b = struct('c',{},'d',{}) .b .c .d a= b: [0x0 struct] >> fieldnames(a.b) ans = 'c' 'd' 5、使用repmat函数,创建结构数组复本 >>Student=repmat(struct('name','Way','age',26,'grade',uint16(1)),1,2) Student = 1x2 struct array with fields: name age grade >> Student=repmat(struct('name','Way','age',26,'grade',uint16(1)),1,3) Student = 1x3 struct array with fields: name age grade 结构数组应用举例 符号计算工具箱中的solve函数 解方程组 s = solve( f1 , f2 , ... , fn , v1 , v2 , ... , vn) 求解由 f1 , f2 , ... , fn 确定的方程组关于 v1 , v2 , ... , vn 的解 返回值 s 是一个结构数组,如果要显示(引用)每个解, 使用 s.v1,s.v2 若不提供v1 , v2 , ... , vN ,Matlab会自动确定默认变量。 x y z 1 解方程组: x z 2 x3 y 2 eq1 = 'x + y - z = 1' eq2 = 'x + z = 2' eq3 = 'x^3 + y = 2' s = solve(eq1,eq2,eq3) x = s.x y = s.y z = s.z s= x: [3x1 sym] y: [3x1 sym] z: [3x1 sym] x= y= z= 1 1 1 1/2*5^(1/2)-1/2 -5^(1/2)+4 -1/2*5^(1/2)+5/2 -1/2*5^(1/2)-1/2 5^(1/2)+4 1/2*5^(1/2)+5/2 x(1),y(1),z(1)是方程组的第 1 组解 x(2),y(2),z(2)是方程组的第 2 组解 x(3),y(3),z(3)是方程组的第 3 组解 uy 2 vz w 0 y ? z ? y z w 0 clc; clear all; syms u v w y z eq1 = u*y^2 + v*z + w; eq2 = y + z + w; s = solve(eq1,eq2,y,z) 二、结构数组的基本操作 1、访问结构标量包含的记录 structName.fieldName S = load('clown.mat') S= 20 40 60 X: [200x320 double] map: [81x3 double] caption: [2x1 char] 80 100 120 140 160 180 200 image(S.X) colormap(S.map) 50 100 150 200 250 300 5 10 15 20 upperLeft = S.X(1:50,1:80); image(upperLeft); 25 30 35 40 45 50 10 20 30 40 50 60 70 80 2、访问结构数组中包含的记录 structName(indices).fieldName S(2) = load('mandrill.mat') 50 100 150 S= 200 250 1x2 struct array with fields: 300 350 X map caption image(S(2).X) colormap(S(2).map) 400 450 50 100 150 200 250 300 350 400 450 500 5 10 15 20 25 30 upperLeft = S(1).X(1:50,1:80); image(upperLeft) 35 40 45 50 10 20 30 40 50 60 70 80 3、访问嵌套结构中的数据 structName(index).nestedStructName(index).fieldName(indices) s.n.a = ones(3); s.n.b = eye(4); s.n.c = magic(5); s 访问 field b的第三行: third_row_b = s.n.b(3,:) .n s(1).n(2).a = 2 * ones(3); s(1).n(2).b = 2 * eye(4); s(1).n(2).c = 2 * magic(5); s(2).n(1).a s(2).n(2).a s(2).n(1).b s(2).n(2).b s(2).n(1).c s(2).n(2).c = = = = = = '1a'; '2a'; '1b'; '2b'; '1c'; '2c'; 访问图中红色方框内 的内容: part_two_eye = s(1).n(2).b(1:2,1:2) 4、同时访问结构数组同一字段(field)的数据 s(1).f = 1; s(2).f = 'two'; s(3).f = 3 * ones(3); 使用 s(1:3).f 或 s.f 可同时访问数组中每个元素的字段f, 返回结果为逗号分隔列表(a comma-separated list),可将返 回结果赋值给多个变量,或将返回结果创建为一元胞数组, 赋值给一个单独的变量。 ans = 1 [v1, v2, v3] = s.f 变量数目应与返回的列表元素数目相同 ans = two ans = 3 3 3 3 3 3 c = {s.f} 3 3 3 若结构数组的每个元素的同一field包含的数据类型都相同, 且能构造成一个矩形形式,则可以使用方括号[ ] 将返回的逗 号分隔列表并置成一个同类型数组。 nums(1).f = 1; nums(2).f = 2; nums(3).f = 3; allNums = [nums.f] allNums = 1 2 3 三、结构操作函数 函数 说明 struct 创建结构或其他数据类型转变成结构 fieldnames 获取结构的字段名称 getfield 获取结构字段的数据 setfield 设置结构字段的数据 rmfield 删除结构的指定字段 isfield 判断给定的字符串是否为结构的字段名称 isstruct 判断给定的数据对象是否为数据类型 oderfields 将结构字段排序 structfun 将函数作用到结构标量的每个field Arrayfun 将函数作用到数组的每个元素 fieldnames函数(获取结构的字段名称) names = fieldnames(s) s(1,1).name s(1,1).ID = s(2,1).name s(2,1).ID = = 'alice'; 0; = 'gertrude'; 1; names = fieldnames(s) names = 'name' 'ID' getfield函数:获取结构字段的数据 value = getfield(struct, ‘field’) 这里struct为结构标量,与 value = struct.field的功能相同 value = getfield(struct,{sIndx1,...,sIndxM},'field',{fIndx1,...,fIndxN}) 与value = struct(sIndx1,...,sIndxM).field(fIndx1,...,fIndxN)功能相同 getfield 函数允许多个 field 和 fIndx; 所有的索引 Indx 输入都是可选的; 若未指定索引,getfield 函数返回第一个索引对应的数据; 若指定冒号:作为索引输入,应将其放在一对单引号中: ':' 例:matlab中的what函数能够获取当前文件夹中与Matlab相关 的文件信息,其返回结果为一个结构数组。下面的语句能够找 出扩展名为.m 的文件: files = getfield(what, 'm'); 也可以将what的返回结果赋值给一个变量,然后访问名 为m的field: templist = what; files = templist.m; 例:访问结构中嵌套field中的数据 level = 5; semester = 'Fall'; subject = 'Math'; student = 'John_Doe'; field_names = {semester subject student}; % Add data to a structure named grades. grades(level).(semester).(subject).(student)(10,21:30) = ... [85, 89, 76, 93, 85, 91, 68, 84, 95, 73]; % Retrieve the data added. getfield(grades, {level}, field_names{:}, {10,21:30}) 访问指定field的第10行的所有数据: getfield(grades, {level}, field_names{:}, {10,':'}) setfield函数:设置结构字段的数据 s = setfield(s,‘field’,value) s为 1×1 结构, 将指定的field的内容设置为value,相当于 s.field = value 。若s不包含指定的 field,则会创建该 field并赋值。 setfiled函数还可以同时设置多个filed的内容: s = setfield(s,{sIndx1,...,sIndxM},'field',{fIndx1,...,fIndxN},value) 相当于: s(sIndx1,...,sIndxM).field(fIndx1,...,fIndxN) = value。 若s或任一fields为非标量结构,则必须指定索引Indx,反之,Indx 为可选项。 若用冒号: 指定索引,必须用单引号把冒号括起来: ‘:’。 setfield函数举例 % 给包含嵌套fields的结构赋值 grades = []; level = 5; semester = 'Fall'; subject = 'Math'; student = 'John_Doe'; fieldnames = {semester subject student} newGrades_Doe = [85, 89, 76, 93, 85, 91, 68, 84, 95, 73]; grades = setfield(grades, {level}, ... fieldnames{:}, {10, 21:30}, ... newGrades_Doe); % 查看内容 grades(level).(semester).(subject).(student)(10, 21:30) % 删除指定field的第十行,用冒号:指定所有的列 grades = setfield(grades, {level}, fieldnames{:}, {10,':'}, []); orderfields函数:将结构字段排序 s = orderfields(s1) 按字典排序对结构 s1 中的fields进行排序,生成新结构s s = orderfields(s1, s2) 按结构s2中fields的顺序对结构s1中的fileds进行排序,生成 新结构s,s1、s2中的 fields必须相同. s = orderfields(s1, c) 按元胞数组c中的顺序对结构s1中的 fields进行排序,生成 新结构s,结构s1的fields和元胞数组 c中存储的fields名称必须相同。 s = orderfields(s1, perm) 按置换向量perm中指定的索引顺序对结构 s1中的fields 进行排序,生成新结构s, 若 s1 有N 个field,则 perm的元素由数字1到N的组成。 这在对多个结构按同一排序规则进行排序时经常使用。 [s, perm] = orderfields(...) 按指定的排序规则进行排序,返回结构s 及相应的置换 向量perm。 orderfields函数举例: 创建结构s。 s = struct(‘b’, 2.1, 'c', 3.2, 'a', 1.3) s= b: 2.1000 c: 3.2000 a: 1.3000 对s中的field按字典顺序,生成结构snew: snew = orderfields(s) snew = a: 1.3000 b: 2.1000 c: 3.2000 按元胞数组指定的顺序对s进行排序,生成新结构snew,以及对应的置 换向量perm: [snew, perm] = orderfields(s, {'b', 'a', 'c'}) snew = b: 2.1000 a: 1.3000 c: 3.2000 perm = 1 3 2 创建结构 s2, 与s有相同的fieldnames。 s2 = struct('b', 3, 'c', 7, 'a', 4) s2 = b: 3 c: 7 a: 4 按perm中指定的置换顺序对s2进行排序,生成新结构snew: snew = orderfields(s2, perm) snew = b: 3 a: 4 c: 7 rmfield函数:删除结构的指定字段 s = rmfield(s,field) 从结构s中删除指定的field。使用字符串元 胞数组指定多个field。 删除一个Field 定义一个标量结构s,有 三个field: a, b, c. 删除field :b. s.a = 1; s.b = 2; s.c = 3; field = 'b'; s = rmfield(s,field) s= a: 1 c: 3 删除多个Fields 定义一个标量结构,有四个 S.first = 1; field: first, second, third, and S.second = 2; fourth. S.third = 3; S.fourth = 4; 删除 fields: first 、fourth. fields = {'first','fourth'}; S = rmfield(S,fields) S= second: 2 third: 3 isfield函数:判断给定的字符串是否为结构的字段名称 tf = isfield(S, ‘fieldname’) 检查结构S中是否包含名为fieldname的field,若包含, 则返回逻辑1 (true) ,反之,返回逻辑0 (false) 。若 S不是结构数组,返回 逻 辑0 (false) 。 tf = isfield(S, C) 检查结构S中是否包含元胞数组C中指定的field,返回值tf为一 逻辑数组,若S中包含C{m,n}指定的field,则tf(m,n)为逻辑1 (true) ,反之, 返回逻辑0 (false) Note 若fieldname为空,则isfield返回逻辑0 (false) 。 Example 1 — Single Fieldname Syntax Given the following MATLAB® structure, patient.name = 'John Doe'; patient.billing = 127.00; patient.test = [79 75 73; 180 178 177.5; 220 210 205]; isfield identifies billing as a field of that structure. isfield(patient,'billing') ans = 1 Example 2 — Multiple Fieldname Syntax Check structure S for any of four possible fieldnames. Only the first is found, so the first element of the return value is set to true: S = struct('one', 1, 'two', 2); fields = isfield(S, {'two', 'pi', 'One', 3.14}) fields = 1 0 0 0 isstruct函数:判断给定的数据对象是否为结构类型 tf = isstruct(A) 若A为结构,则返回逻辑1 (true),反之,返回逻辑0 (false) Examples patient.name = 'John Doe'; patient.billing = 127.00; patient.test = [79 75 73; 180 178 177.5; 220 210 205]; isstruct(patient) ans = 1 cell2struct函数:将元胞数组转变成为结构 structArray = cell2struct(cellArray, fields, dim) fields:字符数组,或字符串元胞数组,指定 field 名称 dim:指定使用cell array 的哪一个维度来创建structure array 若field由N行元胞数组的行确定,需指定 N个 field 名称,dim为1 若field由M列元胞数组的列确定,需指定M个 field 名称,dim为2 例:表格中数据为某公司的员工信息。行为员工所属部门,列为 员工的工作年限。可以考虑先使用元胞数组输入相应的信息。 5 Years 10 Years 15 Years Development Lee, Reed, Hill Dean, Frye Lane, Fox, King Sales Howe, Burns Kirby, Ford Hall Price Clark, Shea Sims Quality Bates, Gray Nash Kay, Chase Documentation Lloyd, Young Ryan, Hart, Roy Marsh Management 创建元胞数组输入员工信息: devel = {{'Lee','Reed','Hill'}, {'Dean','Frye'},{'Lane','Fox','King'}}; sales = {{'Howe','Burns'}, {'Kirby','Ford'}, {'Hall'}}; mgmt = {{'Price'}, {'Clark','Shea'}, {'Sims'}}; qual = {{'Bates','Gray'}, {'Nash'}, {'Kay','Chase'}}; docu = {{'Lloyd','Young'}, {'Ryan','Hart','Roy'}, {'Marsh'}}; employees = [devel; sales; mgmt; qual; docu] employees = {1x3 cell} {1x2 cell} {1x1 cell} {1x2 cell} {1x2 cell} {1x2 cell} {1x2 cell} {1x2 cell} {1x1 cell} {1x3 cell} {1x3 cell} {1x1 cell} {1x1 cell} {1x2 cell} {1x1 cell} 按第一维(行)把元胞数组转为结构: 把 5×3元胞数组按第一维(行)构造为一个 3×1的有5个field 结 构数组:元胞数组的每一行成为结构数组的一个field rowHeadings = {'development', 'sales', 'management', ... 'quality', 'documentation'}; depts = cell2struct(employees, rowHeadings, 1) depts = 3x1 struct array with fields: development sales management quality documentation 查看Development 中工作年限为10 年的员工: depts(1:2).development ans = 'Lee' 'Reed' 'Hill' ans = 'Dean' 'Frye' 按第二维(列)把元胞数组转为结构: 把5×3元胞数组按第二维(列)构造为一个 5×1 有3个field的 结构数组:元胞数组的每一列成为结构数组的一个field colHeadings = {'fiveYears' 'tenYears' 'fifteenYears'}; years = cell2struct(employees, colHeadings, 2) years = 5x1 struct array with fields: fiveYears tenYears fifteenYears 查看Sales和Documentation 部门中工作年限为5年的员工: [~, sales_5years, ~, ~, docu_5years] = years.fiveYears sales_5years = 'Howe' 'Burns' docu_5years = 'Lloyd' 'Young' 将元胞数组的一部分转为结构数组: 例:将元胞数组的第一行和最后一行转为结构数组(按行进 行转换),生成 3×1 有2个field的结构数组。 rowHeadings = {'development', 'documentation'}; depts = cell2struct(employees([1,5],:), rowHeadings, 1) depts = 3x1 struct array with fields: development documentation 查看这些部门中不同工作年限的所有员工: for k=1:3 depts(k,:) end ans = development: {'Lee' 'Reed' 'Hill'} documentation: {'Lloyd' 'Young'} ans = development: {'Dean' 'Frye'} documentation: {'Ryan' 'Hart' 'Roy'} ans = development: {'Lane' 'Fox' 'King'} documentation: {'Marsh'} struct2cell函数:将结构转变成为元胞数组 c = struct2cell(s) 将 m×n 维结构数组 s (有 p个 fields) 转为 p×m×n元胞数组 c. clear s s.category = 'tree'; s.height = 37.4; s.name = 'birch'; s= category: 'tree' height: 37.4000 name: 'birch‘ c = struct2cell(s) c= 'tree' [37.4000] 'birch' structfun函数:将函数作用到结构标量的每个field [A1,...,An] = structfun(func,S) S:结构标量(Scalar structure) func:函数句柄,函数的输入参数为S的每个field,函数有n个输出参数 A1,...,An:n个数组,元素为函数func的输出 [A1,...,An] = structfun(func,S,Name,Value) Name:指定额外的选项,可以是 ‘UniformOutput’ 或 ‘ErrorHandler’ Value:指定额外选项的具体参数 ‘UniformOutput‘ 默认为true(1) :对所有的输入参数field,函数func输出应为 元胞数组或标量(类型、大小相同), structfun函数将这些输出合并为同类 型的数组 A1,...,An。 ‘UniformOutput‘ 设为 false (0)时:对每个输入field,函数func的输出可以为任 意类型、任意大小,structfun函数将输出合并为结构标量( scalar structures) A1,...,An,它们与输入 S具有相同的field。 s.f1 = 'Sunday'; s.f2 = 'Monday'; s.f3 = 'Tuesday'; s.f4 = 'Wednesday'; s.f5 = 'Thursday'; s.f6 = 'Friday'; s.f7 = 'Saturday'; 例1:返回 s 中各个field中的字符串的字符数目 lengths = structfun(@numel, s) 例2:截取 s 的各个field中文本的前三个字符,因输出为非标量 ( nonscalar),故应设 UniformOutput 为 false。 @(x) 用来创建匿 名函数。 shortNames = structfun(@(x) ( x(1:3) ), s, 'UniformOutput', false) 例3:定义并调用一个用户自定义的错误处理函数。 function result = errorfun(errorinfo, field) warning(errorinfo.identifier, errorinfo.message); result = NaN; 保存为errorfun.m end mystruct.f1 = 'text'; myresult = structfun(@(x) x^2, mystruct, 'ErrorHandler', @errorfun) arrayfun函数:将函数作用到数组的每个元素 [B1,...,Bm] = arrayfun(func,A1,...,An) func:函数句柄,函数有n个的输入参数,m个输出参数 A1,...,An:n个同维数组, 数组可以是numeric, character, logical, cell, structure, or user-defined object arrays,每个数组对应的元素作为函数func的输入参数 B1,...,Bm:m个数组,每个数组对应的元素为函数func的输出,相当于: [B1(i),...,Bm(i)] = func(A1{i},...,An{i}). Arrayfun函数执行时,不按某种特定的顺序调用 func函数 。 [B1,...,Bm] = arrayfun(func,A1,...,An,Name,Value) Name:指定额外的选项,可以是 ‘UniformOutput’ 或 ‘ErrorHandler’ Value:指定额外选项的具体参数 ‘UniformOutput‘ 默认为true(1) :对所有的输入参数field,函数func输出应为元胞 数组或标量(类型、大小相同), arrayfun函数将这些输出合并为同类型的数组 B1,...,Bm 。 ‘UniformOutput‘ 设为 false (0)时:对每个输入field,函数func的输出可以为任意类 型、任意大小,arrayfun函数将输出合并为元胞数组 B1,...,Bm。 Examples:To run the examples in this section, create a nonscalar structure array with arrays of different sizes in field f1. s(1).f1 = rand(3, 6); s(2).f1 = magic(12); s(3).f1 = ones(5, 10); Count the number of elements in each f1 field. The syntax @(x) creates an anonymous function. counts = arrayfun(@(x) numel(x.f1), s) counts = 18 144 50 Compute the size of each array in the f1 fields. [nrows, ncols] = arrayfun(@(x) size(x.f1), s)This code returns nrows = 3 12 5 ncols = 6 12 10 Compute the mean of each column in the f1 fields of s. Because the output is nonscalar, set UniformOutput to false. averages = arrayfun(@(x) mean(x.f1), s, 'UniformOutput', false) averages = [1x6 double] [1x12 double] [1x10 double] Create additional nonscalar structures t and u, and test for equality between the arrays in fields f1 across structures s, t, and u. t = s; t(1).f1(:)=0; u = s; u(2).f1(:)=0; same = arrayfun(@(x,y,z) isequal(x.f1, y.f1, z.f1), s, t, u) same = 0 0 1