¿Hay un foreach en MATLAB? Si es así, ¿cómo se comporta si los datos subyacentes cambian?


171

¿Hay una estructura foreach en MATLAB? Si es así, ¿qué sucede si los datos subyacentes cambian (es decir, si se agregan objetos al conjunto)?

Respuestas:


147

El bucle FOR de MATLAB es de naturaleza estática; no puede modificar la variable de bucle entre iteraciones, a diferencia de la estructura de bucle for (inicialización; condición; incremento) en otros idiomas. Esto significa que el siguiente código siempre imprime 1, 2, 3, 4, 5 independientemente del valor de B.

A = 1:5;

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

Si desea poder responder a los cambios en la estructura de datos durante las iteraciones, un ciclo WHILE puede ser más apropiado --- podrá probar la condición del ciclo en cada iteración y establecer el valor de la variable del ciclo ( s) como desee:

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

Por cierto, el ciclo for-each en Java (y posiblemente en otros lenguajes) produce un comportamiento no especificado cuando la estructura de datos se modifica durante la iteración. Si necesita modificar la estructura de datos, debe usar una instancia Iterator apropiada que permita agregar y eliminar elementos en la colección que está iterando. La buena noticia es que MATLAB admite objetos Java, por lo que puede hacer algo como esto:

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
Si B no está definido, su primer ejemplo no imprime 1-5. Se imprime Undefined function or variable 'B'.
Kleist

3
Para el primer ejemplo, asegúrese de que Asea ​​un vector de fila, no un vector de columna. Si Aes una matriz, cada k será un vector de columna de esa matriz. Entonces, transponer ( A') o vectorizar ( A(:)') si es necesario.
yuk

3
-1 Yo no creo similar a Java de código debe ser su primera elección manera de trabajar con Matlab en .marchivos.
bobobobo

1
saludos desde el futuro; venimos con muchas soluciones al problema de invalidación de iterador.
Dmitry

90

Zach tiene razón sobre la respuesta directa a la pregunta.

Una nota al margen interesante es que los siguientes dos bucles no se ejecutan igual:

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

El primer bucle crea una variable ique es escalar y la itera como un bucle C for. Tenga en cuenta que si modifica ien el cuerpo del bucle, el valor modificado se ignorará, como dice Zach. En el segundo caso, Matlab crea una matriz de 10k elementos, luego recorre todos los elementos de la matriz.

Lo que esto significa es que

for i=1:inf
  % do something
end

funciona, pero

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

no lo hace (porque este requeriría asignar memoria infinita). Vea el blog de Loren para más detalles.

También tenga en cuenta que puede iterar sobre matrices de celdas.


2
Sí, me sorprendió esto cuando me encontré con él. Esta optimización de matrices en realidad tiene lugar en muchos lugares. Si usa la notación de corchetes, a veces verá advertencias de rendimiento en el editor de Matlab que le dicen que cree que puede optimizar la asignación de la matriz si lo permite.
Sr. Fooz el

Escuché que Matlab tiene una evaluación perezosa ahora. Si no, tenemos la tecnología para implementarlos.
Dmitry

19

El MATLAB bucle for básicamente permite una gran flexibilidad, incluida lafuncionalidad Aquí algunos ejemplos:

1) Definir inicio, incremento e índice final

for test = 1:3:9
   test
end

2) Bucle sobre el vector

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

3) Bucle sobre cadena

for test = 'hello'
   test
end

4) Bucle sobre una matriz de celdas unidimensionales

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

5) Bucle sobre una matriz de celdas bidimensionales

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

6) Use nombres de campo de matrices de estructura

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

44
Con la matriz de celdas, tenga en cuenta que iterará sobre las columnas de la matriz de celdas.
Evgeni Sergeev

17

Si está intentando recorrer una matriz de celdas y aplicar algo a cada elemento de la celda, consulte cellfun. También hay arrayfun, bsxfuny structfunque puede simplificar su programa.


Sin embargo, por experiencia, diría que su rendimiento es igual o peor que escribir un for-loop, mejor aspecto y quién sabe que podrían mejorar en el futuro.

14

¡Oh! buena pregunta

El bucle for de Matlab toma una matriz como entrada e itera sobre sus columnas. Matlab también maneja prácticamente todo por valor (sin pasar por referencia), por lo que esperaría que tome una instantánea de la entrada del bucle for para que sea inmutable.

Aquí hay un ejemplo que puede ayudar a ilustrar:

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

Al iterar sobre conjuntos de celdas de cadenas, la variable de bucle (llamémosla f) se convierte en un conjunto de celdas de un solo elemento. Tener que escribir en f{1}todas partes se vuelve tedioso, y modificar la variable de bucle proporciona una solución limpia.

% 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

Digamos que tiene una matriz de datos:

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

entonces puedes 'predecirlo' así:

for i = n, i, end

Esto hará eco de cada elemento en n (¡pero, por supuesto, también es posible reemplazar la i con cosas más interesantes!)


4

Creo que esto es lo que realmente quiere el OP:

array = -1:0.1:10

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

Eso solo imprime 10 ya que numel(array)es el número de elementos en la matriz. quizás quisiste decir 1:numel(array)?
Kleist

¿No for i = -1:0.1:10; disp(i); end;sería mejor?
Oriol

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.