如何在MATLAB中迭代n维矩阵中的每个元素?

时间:2009-04-17 02:12:19

标签: arrays matlab matrix multidimensional-array iteration

我有问题。我需要在MATLAB中遍历n维矩阵中的每个元素。问题是,我不知道如何为任意数量的维度做这件事。我知道我可以说

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

等等,但有没有办法为任意数量的维度做这件事?

8 个答案:

答案 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)。您可以使用其他一些技巧:ARRAYFUNCELLFUN

让我们首先假设您有一个函数要应用于 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)

另一个技巧是使用ind2subsub2ind。结合numelsize,这可以让您执行以下操作,创建一个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表示法。