Y a-t-il un foreach dans MATLAB? Si tel est le cas, comment se comporte-t-il si les données sous-jacentes changent?


171

Existe-t-il une structure foreach dans MATLAB? Si oui, que se passe-t-il si les données sous-jacentes changent (c'est-à-dire si des objets sont ajoutés à l'ensemble)?

Réponses:


147

La boucle FOR de MATLAB est de nature statique; vous ne pouvez pas modifier la variable de boucle entre les itérations, contrairement à la structure de boucle for (initialisation; condition; incrément) dans d'autres langages. Cela signifie que le code suivant imprime toujours 1, 2, 3, 4, 5 quelle que soit la valeur de B.

A = 1:5;

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

Si vous voulez être en mesure de répondre aux changements dans la structure de données pendant les itérations, une boucle WHILE peut être plus appropriée --- vous serez en mesure de tester la condition de la boucle à chaque itération et de définir la valeur de la variable de boucle ( s) comme vous le souhaitez:

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

Btw, la boucle for-each en Java (et éventuellement dans d'autres langages) produit un comportement non spécifié lorsque la structure de données est modifiée pendant l'itération. Si vous avez besoin de modifier la structure de données, vous devez utiliser une instance Iterator appropriée qui permet l'ajout et la suppression d'éléments dans la collection que vous itérez. La bonne nouvelle est que MATLAB prend en charge les objets Java, vous pouvez donc faire quelque chose comme ceci:

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 n'est pas défini, votre premier exemple n'imprime pas 1-5. Il imprime Undefined function or variable 'B'.
Kleist

3
Pour le premier exemple, assurez-vous qu'il As'agit d'un vecteur ligne et non d'un vecteur colonne. Si Aest une matrice, chaque k sera un vecteur colonne de cette matrice. Donc, transpose ( A') ou vectorize ( A(:)') si nécessaire.
yuk

3
-1 Je ne pense pas que le code de type Java devrait être votre premier choix pour travailler avec Matlab dans des .mfichiers.
bobobobo

1
salutations du futur; nous venons avec de nombreuses solutions au problème d'invalidation d'itérateur.
Dmitry

90

Zach a raison sur la réponse directe à la question.

Une note latérale intéressante est que les deux boucles suivantes ne s'exécutent pas de la même manière:

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

La première boucle crée une variable iqui est un scalaire et l'itère comme une boucle C for. Notez que si vous modifiez idans le corps de la boucle, la valeur modifiée sera ignorée, comme le dit Zach. Dans le second cas, Matlab crée un tableau de 10 000 éléments, puis parcourt tous les éléments du tableau.

Cela signifie que

for i=1:inf
  % do something
end

fonctionne, mais

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

pas (parce que celui-ci nécessiterait d'allouer une mémoire infinie). Voir le blog de Loren pour plus de détails.

Notez également que vous pouvez parcourir des tableaux de cellules.


2
Ouais, j'ai été surpris quand je suis tombé dessus. Cette optimisation des tableaux a en fait lieu à de nombreux endroits. Si vous utilisez la notation entre crochets, vous verrez parfois des avertissements de performances dans l'éditeur Matlab vous indiquant qu'il pense qu'il peut optimiser l'allocation du tableau si vous le laissez.
Mr Fooz

J'entends que Matlab a une évaluation paresseuse maintenant. Sinon, nous avons la technologie pour les mettre en œuvre.
Dmitry

19

La boucle MATLAB for permet une grande flexibilité, y compris laFonctionnalité. Voici quelques exemples:

1) Définir l'index de début, d'incrémentation et de fin

for test = 1:3:9
   test
end

2) Boucle sur le vecteur

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

3) boucle sur chaîne

for test = 'hello'
   test
end

4) Boucle sur un tableau de cellules à une dimension

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

5) Boucle sur un tableau de cellules à deux dimensions

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

6) Utilisez les noms de champ des tableaux de structure

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

4
Avec le tableau de cellules, notez qu'il itérera sur les colonnes du tableau de cellules.
Evgeni Sergeev

17

Si vous essayez de boucler sur un tableau de cellules et d'appliquer quelque chose à chaque élément de la cellule, vérifiez cellfun. Il y a aussi arrayfun, bsxfunet structfunqui peut simplifier votre programme.


Cependant, par expérience, je dirais que leurs performances sont égales ou pires à l'écriture d'une boucle for, plus belle cependant, et qui sait qu'elles pourraient s'améliorer à l'avenir.

14

ooh! question soignée.

La boucle for de Matlab prend une matrice en entrée et itère sur ses colonnes. Matlab gère également pratiquement tout par valeur (pas de passage par référence), donc je m'attendrais à ce qu'il prenne un instantané de l'entrée de la boucle for, donc il est immuable.

voici un exemple qui peut aider à illustrer:

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

Lors de l'itération sur des tableaux de cellules de chaînes, la variable de boucle (appelons-la f) devient un tableau de cellules à un seul élément. Avoir à écrire f{1}partout devient fastidieux et la modification de la variable de boucle fournit une solution de contournement propre.

% 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

Disons que vous avez un tableau de données:

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

alors vous pouvez `` foreach '' comme ceci:

for i = n, i, end

Cela fera écho à tous les éléments de n (mais remplacer le i par des éléments plus intéressants est également possible bien sûr!)


4

Je pense que c'est ce que veut vraiment l'OP:

array = -1:0.1:10

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

Cela affiche juste 10 puisque numel(array)c'est le nombre d'éléments dans le tableau. vous vouliez peut-être dire 1:numel(array)?
Kleist

Ça ne serait pas for i = -1:0.1:10; disp(i); end;mieux?
Oriol

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.