web-dev-qa-db-fra.com

Comment parcourir chaque élément d'une matrice n-dimensionnelle dans MATLAB?

J'ai un problème. J'ai besoin de parcourir chaque élément d'une matrice n-dimensionnelle dans MATLAB. Le problème est que je ne sais pas comment procéder pour un nombre arbitraire de dimensions. Je sais que je peux dire

for i = 1:size(m,1)
    for j = 1:size(m,2)
        for k = 1:size(m,3)

et ainsi de suite, mais existe-t-il un moyen de le faire pour un nombre arbitraire de dimensions?

77
rlbond

Vous pouvez utiliser l'indexation linéaire pour accéder à chaque élément.

for idx = 1:numel(array)
    element = array(idx)
    ....
end

Ceci est utile si vous n’avez pas besoin de savoir où vous en êtes, j, k. Cependant, si vous n'avez pas besoin de savoir à quel index vous vous trouvez, il vaut probablement mieux utiliser arrayfun ()

89
Andrew

L'idée d'un index linéaire pour les tableaux de matlab est importante. Un tableau dans MATLAB n'est en réalité qu'un vecteur d'éléments, enchaîné en mémoire. MATLAB vous permet d'utiliser un index de ligne et de colonne ou un seul index linéaire. Par exemple,

A = magic(3)
A =
     8     1     6
     3     5     7
     4     9     2

A(2,3)
ans =
     7

A(8)
ans =
     7

Nous pouvons voir l'ordre dans lequel les éléments sont stockés en mémoire en déroulant le tableau dans un vecteur.

A(:)
ans =
     8
     3
     4
     1
     5
     9
     6
     7
     2

Comme vous pouvez le constater, le huitième élément est le nombre 7. En fait, la fonction find renvoie ses résultats sous forme d'index linéaire.

find(A>6)
ans =
     1
     6
     8

Le résultat est que nous pouvons accéder à chaque élément d’un tableau n-d général en utilisant une seule boucle. Par exemple, si nous voulions concilier les éléments de A (oui, je sais qu'il y a de meilleures façons de le faire), on pourrait le faire:

B = zeros(size(A));
for i = 1:numel(A)
  B(i) = A(i).^2;
end

B
B =
    64     1    36
     9    25    49
    16    81     4

L'index linéaire est plus utile dans de nombreuses circonstances. La conversion entre l'index linéaire et deux indices dimensionnels (ou plus élevés) est réalisée avec les fonctions sub2ind et ind2sub.

L'index linéaire s'applique en général à n'importe quel tableau de matlab. Vous pouvez donc l'utiliser sur des structures, des tableaux de cellules, etc. Le seul problème avec l'index linéaire, c'est quand ils deviennent trop gros. MATLAB utilise un entier de 32 bits pour stocker ces index. Donc, si votre tableau contient plus d'un total de 2 ^ 32 éléments, l'index linéaire échouera. Ce n’est vraiment qu’un problème si vous utilisez souvent des matrices creuses, ce qui peut occasionnellement poser problème. (Bien que je n'utilise pas une version 64 bits de MATLAB, je pense que le problème a été résolu pour les personnes chanceuses qui le font.)

33
user85109

Comme indiqué dans quelques autres réponses, vous pouvez parcourir tous les éléments d'une matrice A (de n'importe quelle dimension) à l'aide d'un index linéaire de 1 À numel(A) dans une seule boucle for. Vous pouvez également utiliser quelques fonctions: arrayfun et cellfun .

Supposons d'abord que vous souhaitiez appliquer une fonction à chaque élément de A (appelée my_func). Vous créez d’abord un fonction handle à cette fonction:

fcn = @my_func;

Si A est une matrice (de type double, simple, etc.) de dimension arbitraire, vous pouvez utiliser arrayfun pour appliquer my_func À chaque élément:

outArgs = arrayfun(fcn, A);

Si A est un tableau de cellules de dimension arbitraire, vous pouvez utiliser cellfun pour appliquer my_func À chaque cellule:

outArgs = cellfun(fcn, A);

La fonction my_func Doit accepter A en tant qu'entrée. S'il existe des sorties de my_func, Elles sont placées dans outArgs, qui aura la même taille/dimension que A.

Une mise en garde sur les sorties ... si my_func Renvoie des sorties de tailles et de types différents lorsqu'il fonctionne sur différents éléments de A, alors outArgs devra être transformé en une cellule tableau. Ceci est fait en appelant soit arrayfun ou cellfun avec une paire paramètre/valeur supplémentaire:

outArgs = arrayfun(fcn, A, 'UniformOutput', false);
outArgs = cellfun(fcn, A, 'UniformOutput', false);
15
gnovice

Une autre astuce consiste à utiliser ind2sub et sub2ind. En conjonction avec numel et size, cela peut vous permettre d'effectuer des tâches comme celles-ci, qui créent un tableau à N dimensions, puis définissent tous les éléments de la "diagonale" à 1.

d = zeros( 3, 4, 5, 6 ); % Let's pretend this is a user input
nel = numel( d );
sz = size( d );
szargs = cell( 1, ndims( d ) ); % We'll use this with ind2sub in the loop
for ii=1:nel
    [ szargs{:} ] = ind2sub( sz, ii ); % Convert linear index back to subscripts
    if all( [szargs{2:end}] == szargs{1} ) % On the diagonal?
        d( ii ) = 1;
    end
end
13
Edric

ces solutions sont plus rapides (environ 11%) que d'utiliser numel;)

for idx = reshape(array,1,[]),
     element = element + idx;
end

ou

for idx = array(:)',
    element = element + idx;
end

UPD. tnx @rayryeng pour l'erreur détectée dans la dernière réponse


Avertissement

Les informations temporelles auxquelles ce message a fait référence sont incorrectes et inexactes en raison d'une faute de frappe fondamentale (voir le flux de commentaires ci-dessous ainsi que le historique des modifications - regardez spécifiquement la première version de cette réponse). Caveat Emptor .

1
mathcow

Vous pourriez faire une fonction récursive faire le travail

  • Soit L = size(M)
  • Soit idx = zeros(L,1)
  • Prendre length(L) comme profondeur maximale
  • Boucle for idx(depth) = 1:L(depth)
  • Si votre profondeur est length(L), effectuez l'opération élément, sinon appelez à nouveau la fonction avec depth+1

Pas aussi rapidement que les méthodes vectorisées si vous voulez vérifier tous les points, mais si vous n'avez pas besoin d'évaluer la plupart d'entre eux, cela peut vous faire gagner beaucoup de temps.

1
Dennis Jaheruddin