MATLAB中有foreach吗?如果是这样,如果基础数据发生变化,它将如何表现?


170

MATLAB中是否有foreach结构?如果是这样,如果基础数据发生变化(即将对象添加到集合中),会发生什么?

Answers:


146

MATLAB的FOR循环本质上是静态的;与其他语言中的for(initialization; condition; increment)循环结构不同,您无法在迭代之间修改循环变量。这意味着无论B的值如何,以下代码始终打印1、2、3、4、5。

A = 1:5;

for i = A
    A = B;
    disp(i);
end

如果您希望能够在迭代过程中响应数据结构的变化,则WHILE循环可能更合适---您将能够在每次迭代时测试循环条件,并设置循环变量的值( s)如您所愿:

n = 10;
f = n;
while n > 1
    n = n-1;
    f = f*n;
end
disp(['n! = ' num2str(f)])

顺便说一句,在迭代过程中修改数据结构时,Java(以及其他语言)中的for-each循环会产生未指定的行为。如果需要修改数据结构,则应使用适当的Iterator实例,该实例允许添加和删除要迭代的集合中的元素。好消息是MATLAB支持Java对象,因此您可以执行以下操作:

A = java.util.ArrayList();
A.add(1);
A.add(2);
A.add(3);
A.add(4);
A.add(5);

itr = A.listIterator();

while itr.hasNext()

    k = itr.next();
    disp(k);

    % modify data structure while iterating
    itr.remove();
    itr.add(k);

end

1
如果未定义B,则第一个示例不会打印1-5。它打印Undefined function or variable 'B'
Kleist

3
对于第一个示例,请确保它A是行向量,而不是列向量。如果A是矩阵,则每个k将是该矩阵的列向量。因此,如果需要,可以转置(A')或向量化(A(:)')。
yuk

3
-1我认为类似Java的代码应该是在.m文件中使用Matlab的首选方法。
bobobobo 2012年

1
未来的问候;我们提供了很多解决迭代器无效问题的方法。
德米特里

89

扎克(Zach)对问题的直接答案是正确的。

一个有趣的旁注是以下两个循环执行的不同:

for i=1:10000
  % do something
end
for i=[1:10000]
  % do something
end

第一个循环创建一个i标量变量,并像C for循环一样对其进行迭代。请注意,如果您i在循环体中进行修改,则修改的值将被忽略,如Zach所说。在第二种情况下,Matlab创建一个包含10k元素的数组,然后遍历该数组的所有元素。

这意味着

for i=1:inf
  % do something
end

可行,但是

for i=[1:inf]
  % do something
end

不需要(因为这将需要分配无限的内存)。有关详细信息,请参见Loren的博客

另请注意,您可以遍历单元格数组。


2
是的,当我遇到它时,我对此感到惊讶。数组的优化实际上发生在很多地方。如果使用括号符号,有时您会在Matlab编辑器中看到性能警告,告诉您它认为如果您允许它可以优化阵列分配。
2009年

我听说Matlab现在有懒惰的评估。如果没有,我们确实拥有实施它们的技术。
德米特里

19

MATLAB for循环基本上提供了极大的灵活性,包括功能。这里有一些例子:

1)定义开始,增加和结束索引

for test = 1:3:9
   test
end

2)循环矢量

for test = [1, 3, 4]
   test
end

3)遍历字符串

for test = 'hello'
   test
end

4)遍历一维单元格数组

for test = {'hello', 42, datestr(now) ,1:3}
   test
end

5)遍历二维单元阵列

for test = {'hello',42,datestr(now) ; 'world',43,datestr(now+1)}
   test(1)   
   test(2)
   disp('---')
end

6)使用结构数组的字段名

s.a = 1:3 ; s.b = 10  ; 
for test = fieldnames(s)'
   s.(cell2mat(test))
end

4
对于单元格数组,请注意它将在单元格数组的上进行迭代。
Evgeni Sergeev 2014年

17

如果要遍历单元格数组并将某些内容应用于单元格中的每个元素,请签出cellfun。还有arrayfunbsxfunstructfun它可以简化程序。


但是,根据经验,我会说它们的性能与编写for循环,外观更好的性能相同或最差,并且谁知道它们将来会有所改进。

14

哦!整洁的问题。

Matlab的for循环将矩阵作为输入并对其列进行迭代。Matlab实际上还按值处理所有内容(不传递引用),因此我希望它为for循环的输入拍摄快照,因此它是不可变的。

这是一个示例,可能有助于说明:

>> A = zeros(4); A(:) = 1:16

A =

     1     5     9    13
     2     6    10    14
     3     7    11    15
     4     8    12    16

>> i = 1; for col = A; disp(col'); A(:,i) = i; i = i + 1; end;
     1     2     3     4

     5     6     7     8

     9    10    11    12

    13    14    15    16

>> A

A =

     1     2     3     4
     1     2     3     4
     1     2     3     4
     1     2     3     4

7

当遍历字符串的单元格数组时,循环变量(我们称之为f)成为一个单元素单元格数组。必须f{1}到处写都变得很乏味,修改循环变量提供了一种干净的解决方法。

% This example transposes each field of a struct.
s.a = 1:3;
s.b = zeros(2,3);
s % a: [1 2 3]; b: [2x3 double]
for f = fieldnames(s)'
    s.(f{1}) = s.(f{1})';
end
s % a: [3x1 double]; b: [3x2 double]

% Redefining f simplifies the indexing.
for f = fieldnames(s)'
    f = f{1};
    s.(f) = s.(f)';
end
s % back to a: [1 2 3]; b: [2x3 double]

5

假设您有一组数据:

n = [1    2   3   4   6   12  18  51  69  81  ]

那么您可以像这样“ foreach”它:

for i = n, i, end

这将回显n中的每个元素(但是当然也可以用更有趣的东西替换i!)


4

我认为这是OP真正想要的:

array = -1:0.1:10

for i=1:numel(array)
    disp(array(i))
end

由于numel(array)数组中元素的数量,所以只打印10 。也许你的意思是1:numel(array)
Kleist

for i = -1:0.1:10; disp(i); end;更好吗?
Oriol

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.