Comment puis-je itérer chaque élément dans une matrice n-dimensionnelle dans MATLAB?

j'ai un problème. Je dois itérer chaque élément d'une matrice n-dimensionnelle dans MATLAB. Le problème est, Je ne sais pas comment faire 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 est-il une façon de le faire pour un nombre arbitraire de dimensions?

71
demandé sur gnovice 2009-04-17 06:12:19

8 réponses

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

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

c'est utile si vous n'avez pas besoin de savoir ce que je,j,k, Vous êtes. Toutefois, si vous n'avez pas besoin de savoir quel indice vous êtes, vous êtes probablement mieux d'utiliser arrayfun()

83
répondu Andrew 2009-04-17 02:46:41

l'idée d'un index linéaire pour les tableaux dans matlab est importante. Un tableau dans MATLAB est vraiment juste un vecteur d'éléments, tendu dans la mémoire. MATLAB vous permet d'utiliser soit un index de ligne et de colonne, soit un index linéaire simple. 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 les éléments sont stockés dans la 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 voir, le 8ème élément est le nombre 7. En fait, l' la fonction find renvoie ses résultats sous forme d'index linéaire.

find(A>6)
ans =
     1
     6
     8

le résultat est, nous pouvons accéder à chaque élément à tour de rôle d'un tableau n-d général en utilisant une boucle unique. Par exemple, si nous voulions mettre 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

dans de nombreuses circonstances, l'indice linéaire est plus utile. Conversion entre l'indice linéaire et deux indices dimensionnels (ou plus) est accompli avec les fonctions sub2ind et ind2sub.

l'index linéaire s'applique en général à tout tableau de matlab. Vous pouvez donc l'utiliser sur des structures, des réseaux de cellules, etc. Le seul problème avec l'indice linéaire est quand ils deviennent trop grands. MATLAB utilise un entier 32 bits pour stocker ces index. Donc, si votre tableau contient plus qu'un total de 2^32 éléments, l'indice linéaire échouera. Ce n'est vraiment qu'un problème si vous utilisez souvent des matrices éparses, alors que cela causer un problème. (Bien que je n'utilise pas une version 64 bits de MATLAB, je pense que ce problème a été résolu pour les chanceux qui le font.)

33
répondu 2009-04-17 03:13:00

comme indiqué dans quelques autres réponses, vous pouvez itérer sur tous les éléments dans une matrice a (de n'importe quelle dimension) en utilisant un index linéaire de 1 à numel(a) dans un simple pour boucle. Il y a quelques autres trucs que vous pouvez utiliser: ARRAYFUN et CELLFUN .

supposons d'abord que vous avez une fonction que vous voulez appliquer à chaque élément de Un (appelé "my_func"). Vous créez d'abord un poignée de fonction à 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 comme entrée. S'il y a des sorties de "my_func", elles sont placées dans outArgs , qui seront de la même taille/dimension que a .

Une mise en garde sur les produits... si "my_func" renvoie des sorties de tailles et de types différents lorsqu'il fonctionne sur différents éléments de A , alors est exclu. devra être transformé en réseau de cellules. Ceci est fait en appelant soit ARRAYFUN ou CELLFUN avec une paire de paramètres/valeurs supplémentaires:

outArgs = arrayfun(fcn,A,'UniformOutput',false);
outArgs = cellfun(fcn,A,'UniformOutput',false);
15
répondu gnovice 2009-04-17 04:03:32

Une autre astuce consiste à utiliser ind2sub et sub2ind . En conjonction avec numel et size , cela peut vous permettre de faire des choses comme ce qui suit, qui crée un tableau n-dimensionnel, puis définit tous les éléments sur la" diagonale " pour être 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
répondu Edric 2009-04-17 07:04:22

Vous pourriez faire une fonction récursive faire le travail

  • Let L = size(M)
  • Let idx = zeros(L,1)
  • prendre length(L) comme profondeur maximale
  • Boucle for idx(depth) = 1:L(depth)
  • si votre profondeur est length(L) , faites l'opération de l'élément, sinon appelez à nouveau la fonction avec depth+1

pas aussi rapide que les méthodes vectorisées si vous voulez de vérifier tous les points, mais si vous n'avez pas besoin d'évaluer la plupart d'entre eux, il peut être tout à fait un économiseur de temps.

1
répondu Dennis Jaheruddin 2012-11-15 20:44:49

ces solutions sont plus rapides (environ 11%) que l'utilisation de numel ;)

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

ou

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

UPD. tnx @rayryeng pour les erreurs détectées dans la dernière réponse


Avertissement

l'information de synchronisation que ce post a référencé est incorrecte et inexacte en raison d'une faute de frappe fondamentale qui a été faite (voir le flux de commentaires ci-dessous ainsi que le modifier l'histoire - regarder la première version de cette réponse). Caveat Emptor .

1
répondu mathcow 2017-05-23 10:31:14

Si vous plus que les autres utilisations de size vous pouvez voir que vous pouvez réellement obtenir un vecteur de la taille de chaque dimension. Ce lien vous montre la documentation:

www.mathworks.com/access/helpdesk/help/techdoc/ref/size.html

après avoir obtenu le vecteur de taille, itérez sur ce vecteur. Quelque chose comme ceci (pardonnez ma syntaxe puisque je n'ai pas utilisé Matlab depuis l'Université):

d = size(m);
dims = ndims(m);
for dimNumber = 1:dims
   for i = 1:d[dimNumber]
      ...

faites-en une syntaxe Matlab-légale, et je pense que ça ferait ce que vous voulez.

aussi, vous devriez être en mesure de faire L'indexation linéaire comme décrit ici .

-1
répondu Erich Mirabal 2009-04-17 04:28:52

vous voulez simuler n-imité pour les boucles.

itérant à travers n-dimensional array peut être vu comme augmentant le nombre de n-chiffre.

à chaque dimmension nous avons autant de chiffres que la longueur de la dimmension.

exemple:

supposons que nous ayons un tableau(matrix)

int[][][] T=new int[3][4][5];

dans "pour la notation" nous avons:

for(int x=0;x<3;x++)
   for(int y=0;y<4;y++)
       for(int z=0;z<5;z++)
          T[x][y][z]=...

pour simuler ce que vous devrait utiliser la "notation du nombre à n chiffres "

nous avons un numéro à 3 chiffres, avec 3 chiffres pour le premier, 4 pour le deuxième et cinq pour le troisième chiffre

nous devons augmenter le nombre, donc nous obtiendrions la séquence

0 0 0
0 0 1
0 0 2    
0 0 3
0 0 4
0 1 0
0 1 1
0 1 2
0 1 3
0 1 4
0 2 0
0 2 1
0 2 2
0 2 3
0 2 4
0 3 0
0 3 1
0 3 2
0 3 3
0 3 4
and so on

pour que vous puissiez écrire le code pour augmenter un tel nombre de n-chiffres. Vous pouvez le faire de telle façon que vous pouvez commencer avec n'importe quelle valeur du nombre et augmenter/diminuer les chiffres par des nombres. De cette façon, vous pouvez simuler emboîté pour les boucles qui commencent quelque part dans la table et finissent pas à la fin.

Ce n'est pas une tâche facile. Je ne peux malheureusement pas vous aider avec la notation matlab.

-1
répondu bmegli 2010-03-10 13:46:52