Existe um foreach no MATLAB? Em caso afirmativo, como se comporta se os dados subjacentes são alterados?

170

Existe uma estrutura foreach no MATLAB? Se sim, o que acontece se os dados subjacentes forem alterados (ou seja, se objetos forem adicionados ao conjunto)?

Kip
fonte

Respostas:

146

O loop FOR do MATLAB é de natureza estática; você não pode modificar a variável de loop entre iterações, ao contrário da estrutura de loop for (inicialização; condição; incremento) em outros idiomas. Isso significa que o código a seguir sempre imprime 1, 2, 3, 4, 5, independentemente do valor de B.

A = 1:5;

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

Se você deseja responder a alterações na estrutura de dados durante as iterações, um loop WHILE pode ser mais apropriado - você poderá testar a condição do loop a cada iteração e definir o valor da variável do loop ( s) como você deseja:

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

Aliás, o loop for-each em Java (e possivelmente em outras linguagens) produz um comportamento não especificado quando a estrutura de dados é modificada durante a iteração. Se você precisar modificar a estrutura de dados, use uma instância Iterator apropriada que permita a adição e remoção de elementos na coleção que você está iterando. A boa notícia é que o MATLAB suporta objetos Java, para que você possa fazer algo assim:

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
fonte
1
Se B não estiver definido, seu primeiro exemplo não será impresso de 1 a 5. Imprime Undefined function or variable 'B'.
Kleist
3
Para o 1º exemplo, verifique se Aé um vetor de linha, não um vetor de coluna. Se Afor uma matriz, cada k será um vetor de coluna dessa matriz. Portanto, transponha ( A') ou vectorize ( A(:)') se necessário.
yuk
3
-1 Não acho que o código semelhante ao Java deva ser sua primeira maneira de trabalhar com o Matlab em .marquivos.
bobobobo
1
saudações do futuro; nós fornecemos muitas soluções para o problema de invalidação do iterador.
Dmitry
89

Zach está correto sobre a resposta direta à pergunta.

Uma observação interessante é que os dois loops a seguir não executam o mesmo:

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

O primeiro loop cria uma variável iescalar e a itera como um loop for C. Observe que se você modificar ino corpo do loop, o valor modificado será ignorado, como diz Zach. No segundo caso, o Matlab cria uma matriz de 10.000 elementos e, em seguida, percorre todos os elementos da matriz.

O que isso significa é que

for i=1:inf
  % do something
end

funciona, mas

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

não (porque este exigiria a alocação de memória infinita). Veja o blog de Loren para detalhes.

Observe também que você pode iterar sobre matrizes de células.

Mr Fooz
fonte
2
Sim, fiquei surpreso com isso quando me deparei com isso. Essa otimização de matrizes realmente ocorre em muitos lugares. Se você usar a notação entre colchetes, às vezes verá avisos de desempenho no editor Matlab dizendo que ele pode otimizar a alocação da matriz, se você permitir.
Sr. Fooz
Ouvi dizer que o Matlab tem uma avaliação preguiçosa agora. Caso contrário, temos a tecnologia para implementá-los.
Dmitry
19

O MATLAB for loop basicamente permite uma enorme flexibilidade, incluindo ofuncionalidade. Aqui estão alguns exemplos:

1) Definir índice inicial, incremental e final

for test = 1:3:9
   test
end

2) Loop sobre vetor

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

3) Laço sobre a corda

for test = 'hello'
   test
end

4) Loop sobre uma matriz de células unidimensional

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

5) Loop sobre uma matriz de células bidimensional

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

6) Use nomes de campo de matrizes de estrutura

s.a = 1:3 ; s.b = 10  ; 
for test = fieldnames(s)'
   s.(cell2mat(test))
end
BHF
fonte
4
Com a matriz de células, observe que ele irá percorrer as colunas da matriz de células.
Evgeni Sergeev
17

Se você estiver tentando fazer um loop sobre uma matriz de células e aplicar algo a cada elemento da célula, confira cellfun. Há também arrayfun, bsxfune structfunque pode simplificar o seu programa.

Loren
fonte
no entanto, por experiência, diria que o desempenho deles é igual ou pior ao escrever um loop for, com melhor aparência e quem sabe que poderá melhorar no futuro.
14

ooh! questão pura.

O loop for do Matlab pega uma matriz como entrada e itera sobre suas colunas. O Matlab também lida com praticamente tudo por valor (sem passagem por referência), então eu esperaria que fosse necessário um instantâneo da entrada do loop for, tornando-o imutável.

Aqui está um exemplo que pode ajudar 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
Jason S
fonte
7

Ao iterar sobre matrizes de células de cadeias, a variável de loop (vamos chamá-lo f) se torna uma matriz de célula de elemento único. Ter que escrever em f{1}qualquer lugar fica entediante, e modificar a variável de loop fornece uma solução limpa.

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

fonte
5

Digamos que você tenha uma matriz de dados:

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

então você pode 'foreach' assim:

for i = n, i, end

Isso ecoará todos os elementos em n (mas substituir o i por coisas mais interessantes também é possível, é claro!)

Skidder
fonte
4

Eu acho que é isso que o OP realmente quer:

array = -1:0.1:10

for i=1:numel(array)
    disp(array(i))
end
circunferência
fonte
Isso apenas imprime 10, pois numel(array)é o número de elementos na matriz. talvez você quis dizer 1:numel(array)?
Kleist
Não for i = -1:0.1:10; disp(i); end;seria melhor?
Oriol