索引矩阵和数组
MATLAB 允许多种方法来索引(访问)矩阵和数组的元素:
- 下标索引 - 你可以分别在矩阵的每个维度中指定所需元素的位置。
- 线性索引 - 矩阵被视为向量,无论其大小如何。这意味着,你可以使用单个数字指定矩阵中的每个位置。
- 逻辑索引 - 你使用逻辑矩阵(以及
true
和false
值的矩阵),其中你尝试将矩阵的相同维度作为掩码进行索引,以指定要返回的值。
现在使用以下 3 乘 3 矩阵 M
作为示例更详细地解释这三种方法:
>> M = magic(3)
ans =
8 1 6
3 5 7
4 9 2
下标索引
访问元素最直接的方法是指定其行列索引。例如,访问第二行和第三列上的元素:
>> M(2, 3)
ans =
7
提供的下标数量与 M
的维度数量完全匹配(本例中为 2)。
请注意,下标的顺序与数学约定相同:行索引是第一个。此外,MATLAB 索引以 1
开头,而不是像大多数编程语言一样的 0
。
你可以通过为每个坐标传递矢量而不是单个数字来一次索引多个元素。例如,为了获得整个第二行,我们可以指定我们想要第一,第二和第三列:
>> M(2, [1,2,3])
ans =
3 5 7
在 MATLAB 中,使用冒号运算符(即 1:3
)更容易创建向量 [1,2,3]
。你也可以在索引中使用它。要选择整行(或列),MATLAB 允许你只指定:
来提供快捷方式。例如,以下代码也将返回整个第二行
>> M(2, :)
ans =
3 5 7
MATLAB 还提供了一个快捷方式,用于以 end
关键字的形式指定维度的最后一个元素。end
关键字的工作方式与该维度中最后一个元素的编号完全相同。因此,如果你希望列 2
中的所有列到最后一列,你可以使用以下内容编写:
>> M(2, 2:end)
ans =
5 7
下标索引可能是限制性的,因为它不允许从不同的列和行中提取单个值; 它将提取所有行和列的组合。
>> M([2,3], [1,3])
ans =
3 7
4 2
例如,下标索引不能仅提取元素 M(2,1)
或 M(3,3)
。为此,我们必须考虑线性索引。
线性索引
当你仅使用一个维度进行索引时,MATLAB 允许你将 n 维数组视为一维数组。你可以直接访问第一个元素:
>> M(1)
ans =
8
请注意,数组在 MATLAB 中以列主顺序存储,这意味着你可以通过首先向下列来访问元素。所以 M(2)
是第一列的第二个元素,即 3
,M(4)
将是第二列的第一个元素,即
>> M(4)
ans =
1
在 MATLAB 中存在内置函数将下标索引转换为线性索引,反之亦然: sub2ind
和 ind2sub
。你可以手动将下标(r
,c
)转换为线性索引
idx = r + (c-1)*size(M,1)
要理解这一点,如果我们在第一列,那么线性索引将只是行索引。上面的公式适用于此,因为对于 c == 1
,(c-1) == 0
。在下一列中,线性索引是行号加上前一列的所有行。
请注意,end
关键字仍然适用,现在引用数组的最后一个元素即 M(end) == M(end, end) == 2
。
你还可以使用线性索引来索引多个元素。请注意,如果这样做,返回的矩阵将具有与索引向量矩阵相同的形状。
M(2:4)
返回一个行向量,因为 2:4
代表行向量 [2,3,4]
:
>> M(2:4)
ans =
3 4 1
作为另一个例子,M([1,2;3,4])
返回 2 乘 2 的矩阵,因为 [1,2;3,4]
也是 2 乘 2 的矩阵。请参阅以下代码以说服自己:
>> M([1,2;3,4])
ans =
8 3
4 1
请注意,仅使用:
索引将始终返回列向量:
>> M(:)
ans =
8
3
4
1
5
9
6
7
2
此示例还说明了 MATLAB 在使用线性索引时返回元素的顺序。
逻辑索引
第三种索引方法是使用逻辑矩阵,即仅包含 true
或 false
值的矩阵作为掩码来过滤掉你不想要的元素。例如,如果我们想要找到 M
的所有元素大于 5
,我们可以使用逻辑矩阵
>> M > 5
ans =
1 0 1
0 0 1
0 1 0
索引 M
并仅返回大于 5
的值,如下所示:
>> M(M > 5)
ans =
8
9
6
7
如果你想让这些数字保持原位(即保持矩阵的形状),那么你可以分配给逻辑恭维
>> M(~(M > 5)) = NaN
ans =
8 NaN 6
NaN NaN 7
NaN 9 Nan
我们可以通过使用逻辑索引来减少包含 if
和 for
语句的复杂代码块。
采用非向量化(通过使用线性索引已经缩短为单个循环):
for elem = 1:numel(M)
if M(elem) > 5
M(elem) = M(elem) - 2;
end
end
这可以使用逻辑索引缩短为以下代码:
idx = M > 5;
M(idx) = M(idx) - 2;
甚至更短:
M(M > 5) = M(M > 5) - 2;
更多关于索引
更高维矩阵
上面提到的所有方法都归纳为 n 维。如果我们使用三维矩阵 M3 = rand(3,3,3)
作为示例,那么你可以通过写入访问第三维的第二个切片的所有行和列
>> M(:,:,2)
你可以使用线性索引访问第二个切片的第一个元素。线性索引仅在第一个切片的所有行和所有列之后移动到第二个切片。所以该元素的线性索引是
>> M(size(M,1)*size(M,2)+1)
实际上,在 MATLAB 中,每个矩阵都是 n 维的:恰好是大多数其他 n 维的大小都是 1。那么,如果 a = 2
那么 a(1) == 2
(正如人们所期待的那样),还有 a(1, 1) == 2
,就像 a(1, 1, 1) == 2
,a(1, 1, 1, ..., 1) == 2
等等。这些额外尺寸(尺寸为 1
)被称为单一尺寸。命令 squeeze
将删除它们,并且可以使用 permute
来交换维度的顺序(并且如果需要则引入单个维度)。
还可以使用 m 个下标(其中 m <= n)来索引 n 维矩阵。规则是第一个 m-1 下标通常表现,而最后一个(第 m 个)下标引用剩余的(n-m + 1)维度,就像线性索引引用(n-m + 1)维一样阵列。这是一个例子:
>> M = reshape(1:24,[2,3,4]);
>> M(1,1)
ans =
1
>> M(1,10)
ans =
19
>> M(:,:)
ans =
1 3 5 7 9 11 13 15 17 19 21 23
2 4 6 8 10 12 14 16 18 20 22 24
返回元素范围
使用下标索引,如果在多个维度中指定多个元素,MATLAB 将返回每对可能的坐标。例如,如果你尝试 M([1,2],[1,3]),MATLAB 将返回 M(1,1)
和 M(2,3)
,但它也将返回 M(1,3)
和 M(2,1)
。当你查找坐标对列表的元素时,这似乎不直观,但考虑更大矩阵的示例,A = rand(20)
(注意 A
现在是 20
-by-20
),你想要获得右上象限。在这种情况下,不必指定该象限中的每个坐标对(这种情况下将是 100
对),你只需指定 10
行和 10
列即可。切片像这样的矩阵比需要坐标对列表更常见。
如果你确实想要获得坐标对列表,最简单的解决方案是转换为线性索引。考虑一个问题,其中有一个要返回的列索引向量,其中向量的每一行包含要为矩阵的相应行返回的列号。例如
colIdx = [3;2;1]
所以在这种情况下你真的想要回到 (1,3)
,(2,2)
和 (3,1)
的元素。所以使用线性索引:
>> colIdx = [3;2;1];
>> rowIdx = 1:length(colIdx);
>> idx = sub2ind(size(M), rowIdx, colIdx);
>> M(idx)
ans =
6 5 4
多次返回元素
使用下标和线性索引,你还可以通过重复索引来多次返回元素
>> M([1,1,1,2,2,2])
ans =
8 8 8 3 3 3
你可以使用它来复制整个行和列,例如重复第一行和最后一列
>> M([1, 1:end], [1:end, end])
ans =
8 1 6 6
8 1 6 6
3 5 7 7
4 9 2 2
有关更多信息,请参阅此处 。