C'è una foreach in MATLAB? In tal caso, come si comporta se i dati sottostanti cambiano?


171

Esiste una struttura foreach in MATLAB? In tal caso, cosa succede se i dati sottostanti cambiano (ovvero se gli oggetti vengono aggiunti all'insieme)?

Risposte:


147

Il ciclo FOR di MATLAB è di natura statica; non è possibile modificare la variabile del ciclo tra iterazioni, diversamente dalla struttura del ciclo for (inizializzazione; condizione; incremento) in altre lingue. Ciò significa che il seguente codice stampa sempre 1, 2, 3, 4, 5 indipendentemente dal valore di B.

A = 1:5;

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

Se vuoi essere in grado di rispondere ai cambiamenti nella struttura dei dati durante le iterazioni, un ciclo WHILE potrebbe essere più appropriato --- sarai in grado di testare la condizione del ciclo ad ogni iterazione e impostare il valore della variabile del ciclo ( s) come desideri:

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

A proposito, il ciclo for-each in Java (e possibilmente in altre lingue) produce un comportamento non specificato quando la struttura dei dati viene modificata durante l'iterazione. Se è necessario modificare la struttura dei dati, è necessario utilizzare un'istanza Iterator appropriata che consenta l'aggiunta e la rimozione di elementi nella raccolta che si sta ripetendo. La buona notizia è che MATLAB supporta oggetti Java, quindi puoi fare qualcosa del genere:

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
Se B non è definito, il tuo primo esempio non stampa 1-5. Esso stampa Undefined function or variable 'B'.
Kleist,

3
Per il primo esempio assicurati che Asia un vettore di riga, non un vettore di colonna. Se Aè una matrice, ogni k sarà un vettore di colonna da quella matrice. Quindi, trasporre ( A') o vectorize ( A(:)') se necessario.
yuk,

3
-1 Io non credo che Java come il codice dovrebbe essere la vostra prima scelta modo di lavorare con Matlab in .mfile.
bobobobo,

1
saluti dal futuro; arriviamo con molte soluzioni al problema di invalidazione dell'iteratore.
Dmitry,

90

Zach ha ragione sulla risposta diretta alla domanda.

Una nota a margine interessante è che i seguenti due loop non eseguono lo stesso:

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

Il primo ciclo crea una variabile iche è uno scalare e lo itera come un ciclo C per. Nota che se modifichi inel corpo del loop, il valore modificato verrà ignorato, come dice Zach. Nel secondo caso, Matlab crea un array di 10k elementi, quindi cammina tutti gli elementi dell'array.

Ciò significa che

for i=1:inf
  % do something
end

funziona, ma

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

non (perché questo richiederebbe l'allocazione della memoria infinita). Vedi il blog di Loren per i dettagli.

Si noti inoltre che è possibile scorrere su array di celle.


2
Sì, ne sono rimasto sorpreso quando mi sono imbattuto in esso. Questa ottimizzazione delle matrici in realtà avviene in molti luoghi. Se usi la notazione tra parentesi, a volte vedrai degli avvertimenti sulle prestazioni nell'editor Matlab che ti dice che pensa che possa ottimizzare l'allocazione dell'array se lo lasci.
Fooz,

Ho sentito che Matlab ha una valutazione pigra ora. Altrimenti, abbiamo la tecnologia per implementarli.
Dmitry,

19

Il MATLAB per loop sostanzialmente consente un'enorme flessibilità, incluso ilfunzionalità. Ecco alcuni esempi:

1) Definire l'indice di inizio, incremento e fine

for test = 1:3:9
   test
end

2) Passa sopra il vettore

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

3) Loop over string

for test = 'hello'
   test
end

4) Loop su un array di celle unidimensionale

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

5) Loop su un array di celle bidimensionali

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

6) Utilizzare i nomi dei campi degli array di strutture

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

4
Con l'array di celle, tenere presente che eseguirà l'iterazione su colonne dell'array di celle.
Evgeni Sergeev,

17

Se stai cercando di eseguire il loop su un array di celle e applicare qualcosa a ciascun elemento nella cella, dai un'occhiata cellfun. C'è anche arrayfun, bsxfune structfunche può semplificare il tuo programma.


tuttavia, per esperienza, direi che le loro prestazioni sono uguali o peggiori per la scrittura di un for-loop, un aspetto migliore, e chissà che potrebbero migliorare in futuro.

14

ooh! domanda ordinata.

Il ciclo for di Matlab prende una matrice come input e scorre sulle sue colonne. Matlab gestisce anche praticamente tutto in base al valore (nessun riferimento pass-by), quindi mi aspetto che prenda un'istantanea dell'input del ciclo continuo, quindi è immutabile.

ecco un esempio che può aiutare a illustrare:

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

Quando si scorre su array di celle di stringhe, la variabile loop (chiamiamola così f) diventa un array di celle a elemento singolo. Dover scrivere f{1}ovunque diventa noioso e la modifica della variabile loop fornisce una soluzione alternativa.

% 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

Supponiamo che tu abbia una matrice di dati:

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

allora puoi 'foreach' in questo modo:

for i = n, i, end

Questo farà eco ad ogni elemento in n (ma ovviamente è anche possibile sostituire l'i con cose più interessanti!)


4

Penso che questo sia ciò che l'OP vuole davvero:

array = -1:0.1:10

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

Che stampa solo 10 poiché numel(array)è il numero di elementi nella matrice. forse intendevi 1:numel(array)?
Kleist,

Non for i = -1:0.1:10; disp(i); end;sarebbe meglio?
Oriol,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.