逗号分隔的列表
什么是逗号分隔的列表?
当您键入一系列以逗号分隔的数字时,MATLAB® 会创建一个以逗号分隔的列表并单独返回每个值。
1,2,3
ans = 1 ans = 2 ans = 3
当与大型和更复杂的数据结构体(如 MATLAB 结构体和元胞数组)结合使用时,以逗号分隔的列表有助于简化代码。
生成逗号分隔的列表
您可以从元胞数组或 MATLAB 结构体中生成以逗号分隔的列表。
从元胞数组生成列表
当您从元胞数组中提取多个元素时,将得到一个以逗号分隔的列表。定义一个 4×6 元胞数组。
C = cell(4,6); for k = 1:24 C{k} = k*2; end C
C = 4×6 cell array {[2]} {[10]} {[18]} {[26]} {[34]} {[42]} {[4]} {[12]} {[20]} {[28]} {[36]} {[44]} {[6]} {[14]} {[22]} {[30]} {[38]} {[46]} {[8]} {[16]} {[24]} {[32]} {[40]} {[48]}
提取第五列以生成一个以逗号分隔的列表。
C{:,5}
ans = 34 ans = 36 ans = 38 ans = 40
这一结果与显式键入以下列表相同。
C{1,5},C{2,5},C{3,5},C{4,5}
从结构体生成列表
当您提取某结构体数组的一个维度上的一个字段时,将得到一个以逗号分隔的列表。
首先将前面使用的元胞数组转换为一个带有六个字段的 4x1 MATLAB 结构体,这六个字段为:f1
到 f6
。读取所有行的字段 f5
,MATLAB 会返回一个逗号分隔的列表。
S = cell2struct(C,{'f1','f2','f3','f4','f5','f6'},2); S.f5
ans = 34 ans = 36 ans = 38 ans = 40
这一结果与显式键入以下列表相同。
S(1).f5,S(2).f5,S(3).f5,S(4).f5
从逗号分隔的列表分配输出
您可以通过一个简单的赋值语句将逗号分隔列表的任何或所有连续元素分配给变量。定义元胞数组 C
,并将第一行赋给变量 c1
到 c6
。
C = cell(4,6); for k = 1:24 C{k} = k*2; end [c1,c2,c3,c4,c5,c6] = C{1,1:6}; c5
c5 = 34
C{1,1:3}
赋给变量 c1
、c2
和 c3
,并忽略 C{1,4:6}
。[c1,c2,c3] = C{1,1:6};
S = cell2struct(C,{'f1','f2','f3','f4','f5','f6'},2); [sf1,sf2,sf3] = S.f5; sf3
sf3 = 38
deal
函数来实现此目的。为逗号分隔的列表赋值
将多个值分配给逗号分隔的列表的最简单方法是使用 deal
函数。此函数将其输入参量分发给逗号分隔的列表的元素。
此示例使用 deal
覆盖逗号分隔的列表中的每个元素。首先初始化一个二元素列表。此步骤是必要的,因为在使用 :
作为索引时,不能使用以逗号分隔的列表对未定义的变量赋值。有关详细信息,请参阅使用以逗号分隔的列表对未定义变量赋值。
c{1} = []; c{2} = []; c{:}
ans = [] ans = []
使用 deal
覆盖列表中的每个元素。
[c{:}] = deal([10 20],[14 12]); c{:}
ans = 10 20 ans = 14 12
此示例以同样的方式工作,不同的是将值赋给了结构体字段中以逗号分隔的向量列表。
s(1).field1 = [[]]; s(2).field1 = [[]]; s.field1
ans = [] ans = []
使用 deal
覆盖结构体字段。
[s.field1] = deal([10 20],[14 12]); s.field1
ans = 10 20 ans = 14 12
如何使用以逗号分隔的列表
逗号分隔的列表的常见用途如下:
以下各部分提供了将逗号分隔的列表与元胞数组一起使用的示例。其中每个示例也适用于结构体。
构造数组
构造矩阵或数组时,您可以使用逗号分隔的列表来输入一组元素。当您使用 C{:,5}
指定元素列表时,MATLAB 将会插入四个单独的元素。
C = cell(4,6); for k = 1:24 C{k} = k*2; end A = {'Hello',C{:,5},magic(4)}
A = 1×6 cell array {'Hello'} {[34]} {[36]} {[38]} {[40]} {4×4 double}
当您指定 C
元胞本身时,MATLAB 将会插入整个元胞数组。
A = {'Hello',C,magic(4)}
A = 1×3 cell array {'Hello'} {4×6 cell} {4×4 double}
显示数组
使用列表显示整个或部分结构体或元胞数组。
A{:}
ans = 'Hello' ans = 4×6 cell array {[2]} {[10]} {[18]} {[26]} {[34]} {[42]} {[4]} {[12]} {[20]} {[28]} {[36]} {[44]} {[6]} {[14]} {[22]} {[30]} {[38]} {[46]} {[8]} {[16]} {[24]} {[32]} {[40]} {[48]} ans = 16 2 3 13 5 11 10 8 9 7 6 12 4 14 15 1
串联
将逗号分隔的列表放在方括号内,可从列表中提取指定的元素并将这些元素进行串联。
A = [C{:,5:6}]
A = 34 36 38 40 42 44 46 48
用作函数调用参量
编写函数调用代码时,可以列表形式输入各输入参量,并将每个参量用逗号进行分隔。如果您将这些参量存储在某个结构体或元胞数组中,则可以从该结构体或元胞数组生成整个或部分参量列表。传入数量可变的参量时,这会特别有用。
此示例将几个名称-值参量传递给 plot
函数。
X = -pi:pi/10:pi; Y = tan(sin(X)) - sin(tan(X)); C = cell(2,3); C{1,1} = 'LineWidth'; C{2,1} = 2; C{1,2} = 'MarkerEdgeColor'; C{2,2} = 'k'; C{1,3} = 'MarkerFaceColor'; C{2,3} = 'g'; figure plot(X,Y,'--rs',C{:})
用作函数返回值
MATLAB 函数也可以向调用方返回多个值。这些值以列表形式返回,并且每个值用逗号分隔。您可以将逗号分隔的列表与结构体或元胞数组一起使用,而不用列出每个返回值。对于返回值的数量可变的函数,这一用法更为实用。
以下示例向一个元胞数组返回三个值。
C = cell(1,3);
[C{:}] = fileparts('work/mytests/strArrays.mat')
C = 1×3 cell array {'work/mytests'} {'strArrays'} {'.mat'}
快速傅里叶变换示例
fftshift
函数交换数组的每个维度的左半部分和右半部分。对于向量 [0 2 4 6 8 10]
,输出为 [6 8 10 0 2 4]
。对于多维数组,fftshift
沿每个维度执行此交换。
fftshift
使用索引向量来执行交换。对于上面显示的向量,索引 [1 2 3 4 5 6]
经过重新排列以形成新索引 [4 5 6 1 2 3]
。然后,该函数使用此索引向量重新定位各元素。对于多维数组,fftshift
为每个维度构造一个索引向量。逗号分隔的列表使该任务变得很简单。
下面是 fftshift
函数。
function y = fftshift(x) numDims = ndims(x); idx = cell(1,numDims); for k = 1:numDims m = size(x,k); p = ceil(m/2); idx{k} = [p+1:m 1:p]; end y = x(idx{:}); end
该函数将索引向量存储在元胞数组 idx
中。构建此元胞数组相对比较简单。对于 N 维中的每个维度,请确定该维度的大小并计算最接近中点的整数索引。然后,构造一个交换该维度左右部分的向量。
通过使用元胞数组存储索引向量以及使用逗号分隔的列表进行索引运算,fftshift
只需执行单个运算 y = x(idx{:})
即可移动任意维度的数组。如果您使用显式索引,则需要为希望函数处理的每个维度都编写一条 if
语句。
if ndims(x) == 1 y = x(index1); else if ndims(x) == 2 y = x(index1,index2); end end
在没有逗号分隔的列表时处理这种情况的另一种方法是遍历每个维度,每次转换一个维度并移动数据。通过逗号分隔的列表,您只需将数据移动一次。以逗号分隔的列表使得将交换运算推广到任意数量的维度变得容易。
使用以逗号分隔的列表对运算进行故障排除
一些常见的 MATLAB 运算和索引方法不能直接适用于以逗号分隔的列表。本节详细介绍使用以逗号分隔的列表时可能遇到的几个错误,并说明如何解决基本问题。
中间索引生成了以逗号分隔的列表
使用花括号或圆点的复合索引表达式可以生成以逗号分隔的列表。您必须对列表中的各个元素进行索引才能访问它们。
例如,创建一个包含两个 3×3 双精度值矩阵的 1×2 元胞数组。
A = {magic(3),rand(3)}
A = 1×2 cell array {3×3 double} {3×3 double}
使用花括号索引来显示这两个元素。
A{1,:}
ans = 8 1 6 3 5 7 4 9 2 ans = 0.7922 0.0357 0.6787 0.9595 0.8491 0.7577 0.6557 0.9340 0.7431
以这种方式对 A
进行索引会生成以逗号分隔的列表,其中包含该元胞数组所包含的两个矩阵。您不能使用圆括号索引来检索列表中两个矩阵中 (1,2)
处的项。
A{1,:}(1,2)
Intermediate brace '{}' indexing produced a comma-separated list with 2 values, but it must produce a single value when followed by subsequent indexing operations.
要在元胞数组中的两个矩阵中检索 (1,2)
处的项,请分别对元胞进行索引。
A{1,1}(1,2) A{1,2}(1,2)
ans = 1 ans = 0.0357
表达式生成了以逗号分隔的列表,而不是单个值
条件语句、逻辑运算符、循环和 switch
语句的参量不能是以逗号分隔的列表。例如,您不能使用 for
循环直接遍历以逗号分隔的列表的内容。
创建一个由前三个质数组成的元胞数组。
A = cell(1,3); A{1} = 2; A{2} = 3; A{3} = 5;
A{:}
生成一个包含三个值的以逗号分隔的列表。
A{:}
ans = 2 ans = 3 ans = 5
使用 for
循环遍历由 A{:}
错误生成的以逗号分隔的列表。
for c = A{:} disp(c) end
A brace '{}' indexing expression produced a comma-separated list with 3 values where only a single value is allowed.
要遍历 A
的内容,请用方括号将 A{:}
括起来以将这些值串联成一个向量。
for c = [A{:}] disp(c) end
2 3 5
使用简单赋值对多个元素赋值
与数组不同,使用简单赋值将值赋给以逗号分隔的列表的多个元素会出错。例如,定义一个 2×3 元胞数组。
B = cell(2,3);
使用 :
作为 B
的索引将值 5 赋给该数组的所有元胞会出错。
B{:} = 5
Assigning to 6 elements using a simple assignment statement is not supported. Consider using comma-separated list assignment.
要完成这种赋值,一种方法是用方括号将 B{:}
括起来并使用 deal
函数。
[B{:}] = deal(5)
B = 2×3 cell array {[5]} {[5]} {[5]} {[5]} {[5]} {[5]}
使用以逗号分隔的列表对未定义变量赋值
不能使用 :
作为索引将以逗号分隔的列表赋给未定义的变量。在 为逗号分隔的列表赋值 中的示例中,变量 x
在使用 :
作为索引为其赋予新值之前,定义为具有显式索引的以逗号分隔的列表。
x{1} = []; x{2} = []; [x{:}] = deal([10 20],[14 12]); x{:}
ans = 10 20 ans = 14 12
对未初始化的变量执行相同的赋值会出错。
[y{:}] = deal([10 20],[14 12]);
Comma-separated list assignment to a nonexistent variable is not supported when any index is a colon (:). Use explicit indices or define the variable before performing the assignment.
要解决此问题,请以与 x
相同的方式初始化 y
,或使用足够多的显式索引来创建 y
以容纳 deal
函数生成的值的数目。
[y{1:2}] = deal([10 20],[14 12])
y = 1×2 cell array {[10 20]} {[14 12]}