J'ai un problème. J'ai besoin de parcourir chaque élément d'une matrice à n dimensions dans MATLAB. Le problème est que je ne sais pas comment faire cela 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 y a-t-il un moyen de le faire pour un nombre arbitraire de dimensions?
Réponses:
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 en quoi vous êtes i, j, k. Cependant, si vous n'avez pas besoin de savoir à quel index vous vous trouvez, il vaut probablement mieux utiliser arrayfun ()
la source
I = cell(1, ndims(array)); [I{:}] = ind2sub(size(array),idx);
.L'idée d'un index linéaire pour les tableaux dans matlab est importante. Un tableau dans MATLAB n'est en réalité qu'un vecteur d'éléments, étiré en mémoire. MATLAB vous permet d'utiliser soit un index de ligne et de colonne, soit 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 voir, le 8ème élément est le numéro 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 tour à tour d'un tableau nd général en utilisant une seule boucle. Par exemple, si nous voulions mettre au carré les éléments de A (oui, je sais qu'il existe 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
Il existe de nombreuses circonstances dans lesquelles l'indice linéaire est plus utile. La conversion entre l'indice linéaire et les indices à deux dimensions (ou plus) est effectuée avec les fonctions sub2ind et ind2sub.
L'index linéaire s'applique en général à n'importe quel tableau dans matlab. Vous pouvez donc l'utiliser sur des structures, des tableaux de cellules, etc. Le seul problème avec l'index linéaire est quand ils deviennent trop grands. MATLAB utilise un entier 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 un problème que si vous utilisez souvent des matrices éparses, alors que cela posera parfois un problème. (Bien que je n'utilise pas de version 64 bits de MATLAB, je pense que ce problème a été résolu pour les personnes chanceuses qui le font.)
la source
x = ones(1,2^33,'uint8'); x(2^33)
fonctionne comme prévu.Comme indiqué dans quelques autres réponses, vous pouvez parcourir tous les éléments d'une matrice
A
(de n'importe quelle dimension) en utilisant un index linéaire de1
ànumel(A)
dans une seule boucle for. Vous pouvez également utiliser quelques fonctions:arrayfun
etcellfun
.Supposons d'abord que vous ayez une fonction que vous souhaitez appliquer à chaque élément de
A
(appelémy_func
). Vous créez d'abord un descripteur de fonction pour cette fonction:S'il
A
s'agit d'une matrice (de type double, simple, etc.) de dimension arbitraire, vous pouvez utiliserarrayfun
pour appliquermy_func
à chaque élément:S'il
A
s'agit d'un tableau de cellules de dimension arbitraire, vous pouvez utilisercellfun
pour appliquermy_func
à chaque cellule:outArgs = cellfun(fcn, A);
La fonction
my_func
doit accepterA
comme entrée. S'il y a des sorties demy_func
, celles-ci sont placées dansoutArgs
, qui auront la même taille / dimension queA
.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 deA
, alorsoutArgs
devra être transformé en un tableau de cellules. Cela se fait en appelant soitarrayfun
oucellfun
avec une paire paramètre / valeur supplémentaire:outArgs = arrayfun(fcn, A, 'UniformOutput', false); outArgs = cellfun(fcn, A, 'UniformOutput', false);
la source
Une autre astuce consiste à utiliser
ind2sub
etsub2ind
. En conjonction avecnumel
etsize
, cela peut vous permettre de faire des choses comme ce qui suit, qui crée un tableau à N dimensions, puis définit tous les éléments sur la "diagonale" sur 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
la source
Vous pouvez faire en sorte qu'une fonction récursive fasse le travail
L = size(M)
idx = zeros(L,1)
length(L)
comme profondeur maximalefor idx(depth) = 1:L(depth)
length(L)
, effectuez l'opération d'élément, sinon appelez à nouveau la fonction avecdepth+1
Pas aussi rapide 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 être un gain de temps considérable.
la source
ces solutions sont plus rapides (environ 11%) que l'utilisation
numel
;)for idx = reshape(array,1,[]), element = element + idx; end
ou
for idx = array(:)', element = element + idx; end
UPD. tnx @rayryeng pour erreur détectée dans la dernière réponse
Avertissement
Les informations de synchronisation auxquelles ce post a fait référence sont incorrectes et inexactes en raison d'une faute de frappe fondamentale qui a été faite (voir le flux de commentaires ci-dessous ainsi que l' historique des modifications - regardez en particulier la première version de cette réponse). Caveat Emptor .
la source
1 : array(:)
équivaut à1 : array(1)
. Cela n'itère pas tous les éléments, c'est pourquoi vos temps d'exécution sont rapides. De plus,rand
génère des nombres à virgule flottante , ce1 : array(:)
qui produirait un tableau vide car votre instruction essaie de trouver un vecteur croissant avec sa valeur initiale comme 1 avec une valeur de fin comme un nombre à virgule flottante avec une plage d'[0,1)
exclusivité de 1 en augmentation pas de 1. Un tel vecteur n'est pas possible, ce qui donne un vecteur vide. Votrefor
boucle ne s'exécute pas et votre affirmation est donc fausse. -1 vote. Pardon.reshape(...)
.1 : array(:)
dans votre invite de commande après la créationarray
. Obtenez-vous une matrice vide? si oui, votre code ne fonctionne pas. Je quitte mon vote parce que vous donnez de fausses informations.Si vous examinez plus en détail 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, parcourez ce vecteur. Quelque chose comme ça (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 véritable syntaxe légale Matlab, et je pense que cela ferait ce que vous voulez.
De plus, vous devriez pouvoir effectuer l'indexation linéaire comme décrit ici .
la source
Vous souhaitez simuler des boucles for imbriquées.
L'itération à travers un tableau à n dimensions peut être considérée comme une augmentation du nombre à n chiffres.
A chaque dimmension, nous avons autant de chiffres que la longueur de la dimmension.
Exemple:
Supposons que nous ayons un tableau (matrice)
int[][][] T=new int[3][4][5];
en "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 cela, vous devrez utiliser la "notation des nombres à 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 pour obtenir 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
Ainsi, vous pouvez écrire le code pour augmenter ce nombre à n chiffres. Vous pouvez le faire de telle manière que vous pouvez commencer avec n'importe quelle valeur du nombre et augmenter / diminuer les chiffres de n'importe quel nombre. De cette façon, vous pouvez simuler des boucles imbriquées pour qui commencent quelque part dans le tableau et ne se terminent pas à la fin.
Ce n’est cependant pas une tâche facile. Je ne peux malheureusement pas aider avec la notation matlab.
la source