我有问题。我需要在MATLAB中遍历n维矩阵中的每个元素。问题是,我不知道如何为任意数量的维度做这件事。我知道我可以说
for i = 1:size(m,1)
for j = 1:size(m,2)
for k = 1:size(m,3)
等等,但有没有办法为任意数量的维度做这件事?
答案 0 :(得分:89)
您可以使用线性索引来访问每个元素。
for idx = 1:numel(array)
element = array(idx)
....
end
如果你不需要知道你是什么i,j,k,那么这很有用。但是,如果您不需要知道自己的索引,那么最好使用arrayfun()
答案 1 :(得分:33)
matlab中数组的线性索引的想法很重要。 MATLAB中的数组实际上只是元素的向量,在内存中排列。 MATLAB允许您使用行索引和列索引,或单个线性索引。例如,
A = magic(3)
A =
8 1 6
3 5 7
4 9 2
A(2,3)
ans =
7
A(8)
ans =
7
我们可以通过将数组展开到向量中来查看元素存储在内存中的顺序。
A(:)
ans =
8
3
4
1
5
9
6
7
2
如您所见,第8个元素是数字7.实际上,函数find将其结果作为线性索引返回。
find(A>6)
ans =
1
6
8
结果是,我们可以使用单个循环依次访问每个元素的一般n-d数组。例如,如果我们想要对A的元素进行平方(是的,我知道有更好的方法可以做到这一点),可以这样做:
B = zeros(size(A));
for i = 1:numel(A)
B(i) = A(i).^2;
end
B
B =
64 1 36
9 25 49
16 81 4
在许多情况下,线性索引更有用。使用sub2ind和ind2sub函数完成线性索引和两个(或更高)维度下标之间的转换。
线性索引通常适用于matlab中的任何数组。所以你可以在结构,单元格数组等上使用它。线性索引的唯一问题是当它们变得太大时。 MATLAB使用32位整数来存储这些索引。因此,如果您的数组中包含的元素总数超过2 ^ 32个元素,则线性索引将失败。如果你经常使用稀疏矩阵,这实际上只是一个问题,偶尔会导致问题。 (虽然我没有使用64位MATLAB版本,但我相信那些幸运的人已经解决了这个问题。)
答案 2 :(得分:15)
正如其他一些答案中所指出的,您可以使用从 1 到 A (任何维度)中的所有元素单个for循环中的> numel(A)。您可以使用其他一些技巧:ARRAYFUN和CELLFUN。
让我们首先假设您有一个函数要应用于 A (称为“my_func”)的每个元素。您首先为此函数创建function handle:
fcn = @my_func;
如果 A 是任意维度的矩阵(类型为double,single等),则可以使用ARRAYFUN将“my_func”应用于每个元素:
outArgs = arrayfun(fcn,A);
如果 A 是任意维度的单元格数组,您可以使用CELLFUN将“my_func”应用于每个单元格:
outArgs = cellfun(fcn,A);
函数“my_func”必须接受 A 作为输入。如果“my_func”中有任何输出,则会将这些输出放在 outArgs 中,其大小/尺寸与 A 相同。
关于输出的一个警告......如果“my_func”在 A 的不同元素上运行时返回不同大小和类型的输出,那么 outArgs 必须是制作成一个单元格阵列。这是通过使用附加参数/值对调用ARRAYFUN或CELLFUN来完成的:
outArgs = arrayfun(fcn,A,'UniformOutput',false);
outArgs = cellfun(fcn,A,'UniformOutput',false);
答案 3 :(得分:13)
另一个技巧是使用ind2sub
和sub2ind
。结合numel
和size
,这可以让您执行以下操作,创建一个N维数组,然后将“对角线”上的所有元素设置为1。
d = zeros( 3, 4, 5, 6 ); % Let's pretend this is a user input
nel = numel( d );
sz = size( d );
szargs = cell( 1, ndims( d ) ); % We'll use this with ind2sub in the loop
for ii=1:nel
[ szargs{:} ] = ind2sub( sz, ii ); % Convert linear index back to subscripts
if all( [szargs{2:end}] == szargs{1} ) % On the diagonal?
d( ii ) = 1;
end
end
答案 4 :(得分:1)
你可以做一个递归函数来完成工作
L = size(M)
idx = zeros(L,1)
length(L)
作为最大深度for idx(depth) = 1:L(depth)
length(L)
,请执行元素操作,否则使用depth+1
再次调用该函数如果你想检查所有的点,没有矢量化方法那么快,但如果你不需要评估它们中的大多数,那么它可以节省很多时间。
答案 5 :(得分:1)
这些解决方案比使用numel
更快(约11%);)
for idx = reshape(array,1,[]),
element = element + idx;
end
或
for idx = array(:)',
element = element + idx;
end
UPD。 tnx @rayryeng在最后一个回答中检测到错误
此帖子引用的时间信息由于输入的基本错误而不正确且不准确(请参阅下面的评论流以及edit history - 请特别查看此答案的第一个版本)。 Caveat Emptor
答案 6 :(得分:-1)
如果你仔细研究size
的其他用法,你会发现你实际上可以获得每个维度大小的向量。此链接显示文档:
www.mathworks.com/access/helpdesk/help/techdoc/ref/size.html
获取大小向量后,迭代该向量。这样的事情(原谅我的语法,因为我从大学开始就没有使用过Matlab):
d = size(m);
dims = ndims(m);
for dimNumber = 1:dims
for i = 1:d[dimNumber]
...
将它变成实际的Matlab法律语法,我认为它会做你想要的。
此外,您应该能够按照here所述进行线性索引。
答案 7 :(得分:-1)
您想要模拟n-nested for循环。
通过n维数组迭代可以看作是增加n位数。
在每个dimmension,我们有尽可能多的数字与dimmension的长度。
示例:
假设我们有数组(矩阵)
int[][][] T=new int[3][4][5];
在“for notation”中我们有:
for(int x=0;x<3;x++)
for(int y=0;y<4;y++)
for(int z=0;z<5;z++)
T[x][y][z]=...
要模拟这个,你必须使用“n位数字符号”
我们有3位数字,第一位是3位,第二位是4位,第三位是5位
我们必须增加数字,所以我们会得到序列
0 0 0
0 0 1
0 0 2
0 0 3
0 0 4
0 1 0
0 1 1
0 1 2
0 1 3
0 1 4
0 2 0
0 2 1
0 2 2
0 2 3
0 2 4
0 3 0
0 3 1
0 3 2
0 3 3
0 3 4
and so on
因此,您可以编写用于增加此n位数的代码。你可以这样做,你可以从任何数字值开始,并增加/减少任何数字的数字。这样你就可以模拟嵌套的for循环,这些循环从表格的某个地方开始,最后不会结束。
但这不是一件容易的事。不幸的是,我无法帮助matlab表示法。