tags:

views:

6607

answers:

5

Is there a foreach structure in MATLAB? If so, what happens if the underlying data changes (i.e. if objects are added to the set)?

+7  A: 

ooh! neat question.

Matlab's for loop takes a matrix as input and iterates over its columns. Matlab also handles practically everything by value (no pass-by-reference) so I would expect that it takes a snapshot of the for-loop's input so it's immutable.

here's an example which may help illustrate:

>> 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
Jason S
+14  A: 

MATLAB's FOR loop is static in nature; you cannot modify the loop variable between iterations, unlike the for(initialization;condition;increment) loop structure in other languages. This means that the following code always prints 1, 2, 3, 4, 5 regardless of the value of B.

A = 1:5;

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

If you want to be able to respond to changes in the data structure during iterations, a WHILE loop may be more appropriate --- you'll be able to test the loop condition at every iteration, and set the value of the loop variable(s) as you wish.

Btw, the for-each loop in Java (and possibly other languages) produces unspecified behavior when the data structure is modified during iteration. If you need to modify the data structure, you should use an appropriate Iterator instance which allows the addition and removal of elements in the collection you are iterating. The good news is that MATLAB supports Java objects, so you can do something like this:

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
Zach Scrivena
+1 for the java reference
Jason S
+15  A: 

Zach is correct about the direct answer to the question.

An interesting side note is that the following two loops do not execute the same:

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

The first loop creates a variable i that is a scalar and it iterates it like a C for loop. Note that if you modify i in the loop body, the modified value will be ignored, as Zach says. In the second case, Matlab creates a 10k-element array, then it walks all elements of the array.

What this means is that

for i=1:inf
  % do something
end

works, but

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

does not (because this one would require allocating infinite memory). See Loren's blog for details.

Also note that you can iterate over cell arrays.

Mr Fooz
That's a great point! Didn't realize that myself.
Zach Scrivena
Yeah, I was surprised about this when I ran into it. This optimization of arrays actually takes place in many places. If you use bracket notation, sometimes you'll see performance warnings in the Matlab editor telling you it thinks it can optimize out the array allocation if you let it.
Mr Fooz
+1 for pointing out the subtlety
Jason S
+3  A: 

If you are trying to loop over a cell array and apply something to each element in the cell, check out cellfun. There's also arrayfun, bsxfun, and structfun which may simplify your program.

--Loren

Loren
A: 

When iterating over cell arrays of strings, the loop variable (let's call it f) becomes a single-element cell array. Having to write f{1} everywhere gets tedious, and modifying the loop variable provides a clean workaround.

% 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]