Czy jest foreach w MATLAB? Jeśli tak, jak się zachowuje, gdy zmieniają się dane bazowe?


170

Czy w MATLAB jest jakaś struktura? Jeśli tak, co się stanie, jeśli podstawowe dane ulegną zmianie (tj. Jeśli obiekty zostaną dodane do zestawu)?

Odpowiedzi:


146

Pętla FOR w MATLAB-ie ma charakter statyczny; nie można modyfikować zmiennej pętli między iteracjami, w przeciwieństwie do struktury pętli for (inicjalizacja; warunek; przyrost) w innych językach. Oznacza to, że poniższy kod zawsze wypisuje 1, 2, 3, 4, 5 niezależnie od wartości B.

A = 1:5;

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

Jeśli chcesz móc reagować na zmiany w strukturze danych podczas iteracji, pętla WHILE może być bardziej odpowiednia - będziesz mógł przetestować warunek pętli w każdej iteracji i ustawić wartość zmiennej pętli ( s) jak chcesz:

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

Przy okazji, pętla for-each w Javie (i prawdopodobnie w innych językach) powoduje nieokreślone zachowanie, gdy struktura danych jest modyfikowana podczas iteracji. Jeśli potrzebujesz zmodyfikować strukturę danych, powinieneś użyć odpowiedniej instancji Iteratora, która umożliwia dodawanie i usuwanie elementów w kolekcji, którą iterujesz. Dobra wiadomość jest taka, że ​​MATLAB obsługuje obiekty Java, więc możesz zrobić coś takiego:

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
Jeśli B jest niezdefiniowane, w pierwszym przykładzie nie wypisuje się 1-5. To drukuje Undefined function or variable 'B'.
Kleist,

3
W pierwszym przykładzie upewnij się, że Ajest to wektor wierszowy, a nie wektor kolumnowy. Jeśli Ajest macierzą, każde k będzie wektorem kolumnowym z tej macierzy. W razie potrzeby transponuj ( A') lub wektoryzuj ( A(:)').
fuj

3
-1 ja nie myśleć Java podobny kod powinien być pierwszym wyborem sposób do pracy z Matlab w .mplikach.
bobobobo

1
pozdrowienia z przyszłości; mamy mnóstwo rozwiązań problemu unieważnienia iteratorów.
Dmitry,

89

Zach ma rację co do bezpośredniej odpowiedzi na pytanie.

Ciekawą uwagą na marginesie jest to, że następujące dwie pętle nie wykonują tego samego:

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

Pierwsza pętla tworzy zmienną, iktóra jest skalarem i iteruje ją jak pętlę C for. Zwróć uwagę, że jeśli zmodyfikujesz itreść pętli, zmodyfikowana wartość zostanie zignorowana, jak mówi Zach. W drugim przypadku Matlab tworzy 10k-elementową tablicę, a następnie przechodzi przez wszystkie elementy tablicy.

Co to oznacza, że

for i=1:inf
  % do something
end

działa, ale

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

nie (ponieważ ten wymagałby przydzielenia nieskończonej ilości pamięci). Zobacz blog Lorena po szczegóły.

Zauważ również, że możesz iterować po tablicach komórek.


2
Tak, byłem tym zaskoczony, kiedy na to wpadłem. Ta optymalizacja tablic ma faktycznie miejsce w wielu miejscach. Jeśli używasz notacji w nawiasach, czasami zobaczysz ostrzeżenia o wydajności w edytorze Matlab, informujące, że uważa, że ​​może zoptymalizować alokację tablicy, jeśli na to pozwolisz.
Pan Fooz,

Słyszałem, że Matlab leniwie ocenia teraz. Jeśli nie, mamy technologię do ich wdrożenia.
Dmitry,

19

Pętla MATLAB for zasadniczo zapewnia ogromną elastyczność, w tymfunkcjonalność. Oto kilka przykładów:

1) Zdefiniuj indeks początkowy, przyrostowy i końcowy

for test = 1:3:9
   test
end

2) Pętla nad wektorem

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

3) Pętla na sznurku

for test = 'hello'
   test
end

4) Pętla nad jednowymiarową macierzą komórek

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

5) Pętla nad dwuwymiarową macierzą komórek

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

6) Użyj nazw pól tablic struktur

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

4
W przypadku tablicy komórek zwróć uwagę, że będzie ona iterować po kolumnach tablicy komórek.
Evgeni Sergeev

17

Jeśli próbujesz zapętlić tablicę komórek i zastosować coś do każdego elementu w komórce, sprawdź cellfun. Jest też arrayfun, bsxfuni structfunmoże uprościć twój program.


chociaż z doświadczenia powiedziałbym, że ich wydajność jest równa lub gorsza od napisania pętli for, chociaż lepiej wygląda i kto wie, że mogą się poprawić w przyszłości.

14

ooh! fajne pytanie.

Pętla for Matlaba pobiera macierz jako dane wejściowe i iteruje po jej kolumnach. Matlab obsługuje również praktycznie wszystko według wartości (bez przekazywania przez odniesienie), więc spodziewałbym się, że pobiera migawkę wejścia pętli for, więc jest niezmienny.

oto przykład, który może pomóc zilustrować:

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

Podczas iteracji po tablicach komórek zawierających ciągi, zmienna pętli (nazwijmy ją f) staje się jednoelementową tablicą komórek. Pisanie f{1}wszędzie staje się żmudne, a modyfikowanie zmiennej pętli zapewnia przejrzyste obejście.

% 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

Powiedzmy, że masz tablicę danych:

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

możesz to „na zawsze” w ten sposób:

for i = n, i, end

Spowoduje to odbicie każdego elementu w n (ale oczywiście zastąpienie i ciekawszymi rzeczami jest również możliwe!)


4

Myślę, że właśnie tego chce OP:

array = -1:0.1:10

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

To po prostu wypisuje 10, ponieważ numel(array)jest to liczba elementów w tablicy. może miałeś na myśli 1:numel(array)?
Kleist,

Nie for i = -1:0.1:10; disp(i); end;byłoby lepiej?
Oriol

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.