Come faccio a scorrere ogni elemento in una matrice n-dimensionale in MATLAB?

Ho un problema. Ho bisogno di scorrere tutti gli elementi in una matrice n-dimensionale in MATLAB. Il problema è che non so come farlo per un numero arbitrario di dimensioni. So che posso dire

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

e così via, ma c’è un modo per farlo per un numero arbitrario di dimensioni?

È ansible utilizzare l’indicizzazione lineare per accedere a ciascun elemento.

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

Questo è utile se non hai bisogno di sapere cosa io, j, k, tu sei. Tuttavia, se non hai bisogno di sapere quale indice sei, probabilmente stai meglio usando arrayfun ()

L’idea di un indice lineare per gli array in MATLAB è importante. Un array in MATLAB è in realtà solo un vettore di elementi, in memoria. MATLAB consente di utilizzare un indice di riga e colonna o un singolo indice lineare. Per esempio,

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

Possiamo vedere l’ordine in cui gli elementi sono archiviati in memoria srotolando l’array in un vettore.

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

Come puoi vedere, l’ottavo elemento è il numero 7. In effetti, la funzione find restituisce i suoi risultati come un indice lineare.

 find(A>6) ans = 1 6 8 

Il risultato è che possiamo accedere a ciascun elemento a sua volta di un array nd generale utilizzando un singolo ciclo. Per esempio, se volessimo quadrare gli elementi di A (sì, so che ci sono modi migliori per farlo), si potrebbe fare questo:

 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 

Ci sono molte circostanze in cui l’indice lineare è più utile. La conversione tra l’indice lineare e due (o più alti) indici dimensionali viene eseguita con le funzioni sub2ind e ind2sub.

L’indice lineare si applica in generale a qualsiasi matrice in MATLAB. Quindi puoi usarlo su strutture, array di celle, ecc. L’unico problema con l’indice lineare è quando diventano troppo grandi. MATLAB usa un intero a 32 bit per memorizzare questi indici. Quindi se l’array ha più di 2 ^ 32 elementi in totale, l’indice lineare fallirà. È davvero solo un problema se usi spesso matrici sparse, quando occasionalmente questo causerà un problema. (Anche se non uso una versione MATLAB a 64 bit, credo che il problema sia stato risolto per quelle persone fortunate che lo fanno.)

Come indicato in alcune altre risposte, è ansible scorrere tutti gli elementi di una matrice A (di qualsiasi dimensione) usando un indice lineare da 1 a numel (A) in un ciclo for. Ci sono un paio di altri trucchi che puoi usare: ARRAYFUN e CELLFUN .

Supponiamo innanzitutto di avere una funzione che si desidera applicare a ciascun elemento di A (chiamato “my_func”). Per prima cosa create un handle di funzione per questa funzione:

 fcn = @my_func; 

Se A è una matrice (di tipo double, single, ecc.) Di dimensione arbitraria, puoi usare ARRAYFUN per applicare “my_func” a ciascun elemento:

 outArgs = arrayfun(fcn,A); 

Se A è un array di celle di dimensione arbitraria, puoi usare CELLFUN per applicare “my_func” a ogni cella:

 outArgs = cellfun(fcn,A); 

La funzione “my_func” deve accettare A come input. Se ci sono uscite da “my_func”, queste vengono posizionate in outArgs , che avrà la stessa dimensione / dimensione di A.

Un avvertimento sugli output … se “my_func” restituisce output di diverse dimensioni e tipi quando opera su diversi elementi di A , allora outArgs dovrà essere trasformato in un array di celle. Questo viene fatto chiamando ARRAYFUN o CELLFUN con una coppia parametro / valore aggiuntiva:

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

Un altro trucco è usare ind2sub e sub2ind . In combinazione con numel e size , questo ti consente di fare cose come la seguente, che crea una matrice N-dimensionale, e quindi imposta tutti gli elementi sulla “diagonale” come 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 

Potresti fare una funzione ricorsiva per fare il lavoro

  • Sia L = size(M)
  • Lascia che idx = zeros(L,1)
  • Prendi la length(L) come massima profondità
  • Loop for idx(depth) = 1:L(depth)
  • Se la tua profondità è la length(L) , esegui l’operazione dell’elemento, altrimenti chiama nuovamente la funzione con depth+1

Non veloce come i metodi vettorizzati se si desidera controllare tutti i punti, ma se non è necessario valutare la maggior parte di essi può essere abbastanza un risparmio di tempo.

queste soluzioni sono più veloci (circa l’11%) rispetto all’utilizzo di numel 😉

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

o

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

UPD. tnx @rayryeng per errore rilevato nell’ultima risposta


disconoscimento

Le informazioni sul tempo a cui questo post ha fatto riferimento sono errate e imprecise a causa di un errore di battitura fondamentale che è stato fatto (vedi i commenti in streaming qui sotto e la cronologia delle modifiche – in particolare, guarda la prima versione di questa risposta). Caveat Emptor .

Se osservi più a fondo gli altri usi della size , puoi vedere che puoi effettivamente ottenere un vettore della dimensione di ciascuna dimensione. Questo link mostra la documentazione:

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

Dopo aver ottenuto il vettore delle dimensioni, scorrere su quel vettore. Qualcosa del genere (scusa la mia syntax visto che non ho usato Matlab dal college):

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

Rendilo nella vera syntax legale di Matlab, e penso che farebbe ciò che vuoi.

Inoltre, dovresti essere in grado di eseguire l’indicizzazione lineare come descritto qui .

Vuoi simulare n-nested per cicli.

L’iterazione attraverso l’array n-dimensionale può essere vista come un aumento del numero di n cifre.

Ad ogni dimmensione abbiamo tante cifre quante la lunghezza della dimmensione.

Esempio:

Supponiamo di avere una matrice (matrice)

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

in “per notazione” abbiamo:

 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]=... 

per simulare ciò dovresti usare la "notazione numerica a n cifre"

Abbiamo un numero di 3 cifre, con 3 cifre per la prima, 4 per la seconda e cinque per la terza cifra

Dobbiamo aumentare il numero, in modo da ottenere la sequenza

 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 

Quindi puoi scrivere il codice per aumentare tale numero di n cifre. Puoi farlo in modo tale da poter iniziare con qualsiasi valore del numero e aumentare / diminuire le cifre di qualsiasi numero. In questo modo puoi simulare i cicli nidificati che iniziano da qualche parte nel tavolo e terminano non alla fine.

Questo non è un compito facile però. Non posso aiutare sfortunatamente con la notazione MATLAB.