87

我有个问题。我需要遍历 MATLAB 中 n 维矩阵中的每个元素。问题是,我不知道如何对任意数量的维度执行此操作。我知道我可以说

for i = 1:size(m,1)
    for j = 1:size(m,2)
        for k = 1:size(m,3)

等等,但是有没有办法为任意数量的维度做到这一点?

4

8 回答 8

93

您可以使用线性索引来访问每个元素。

for idx = 1:numel(array)
    element = array(idx)
    ....
end

如果您不需要知道 i,j,k, 您所在的位置,这将很有用。但是,如果您不需要知道您所在的索引,您最好使用 arrayfun()

于 2009-04-17T02:46:41.590 回答
35

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

结果是,我们可以使用单个循环依次访问通用 nd 数组的每个元素。例如,如果我们想对 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 版本,但我相信那些幸运的人已经解决了这个问题。)

于 2009-04-17T03:13:00.293 回答
15

正如在其他一些答案中所指出的,您可以在单个 for 循环中使用从to的线性索引A迭代矩阵(任何维度)中的所有元素。您还可以使用几个函数:和.1numel(A)arrayfuncellfun

让我们首先假设您有一个要应用于A(称为my_func)的每个元素的函数。您首先为此函数创建一个函数句柄:

fcn = @my_func;

如果A是任意维度的矩阵(双精度、单精度等),您可以使用它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必须将其制成单元数组。这是通过调用arrayfuncellfun使用附加的参数/值对来完成的:

outArgs = arrayfun(fcn, A, 'UniformOutput', false);
outArgs = cellfun(fcn, A, 'UniformOutput', false);
于 2009-04-17T04:03:32.513 回答
13

另一个技巧是使用ind2suband sub2ind。与numeland结合使用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
于 2009-04-17T07:04:22.140 回答
1

您可以使递归函数完成工作

  • L = size(M)
  • idx = zeros(L,1)
  • length(L)最大深度
  • 环形for idx(depth) = 1:L(depth)
  • 如果您的深度是length(L),请执行元素操作,否则再次调用该函数depth+1

如果您想检查所有点,不如矢量化方法快,但如果您不需要评估其中的大多数点,它可以节省大量时间。

于 2012-11-15T20:44:49.210 回答
1

这些解决方案比使用更快(大约 11%)numel;)

for idx = reshape(array,1,[]),
     element = element + idx;
end

或者

for idx = array(:)',
    element = element + idx;
end

UPD。tnx @rayryeng 在最后一个答案中检测到错误


免责声明

由于出现了根本性的拼写错误,这篇文章引用的时间信息不正确且不准确(请参阅下面的评论流以及编辑历史记录- 特别是查看此答案的第一个版本)。 警告 Emptor

于 2015-04-08T21:55:06.700 回答
-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 法律语法,我认为它会做你想要的。

此外,您应该能够按照此处所述进行线性索引。

于 2009-04-17T02:40:48.670 回答
-1

您想模拟 n 嵌套的 for 循环。

遍历n维数组可以看作是增加n位数。

在每个维度上,我们有与维度长度一样多的数字。

例子:

假设我们有数组(矩阵)

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 表示法。

于 2010-03-10T13:46:52.920 回答