Eu tenho um problema. Eu preciso iterar por meio de cada elemento em uma matriz n-dimensional no MATLAB. O problema é que não sei como fazer isso para um número arbitrário de dimensões. Eu sei que posso dizer
for i = 1:size(m,1)
for j = 1:size(m,2)
for k = 1:size(m,3)
e assim por diante, mas há uma maneira de fazer isso para um número arbitrário de dimensões?
Respostas:
Você pode usar a indexação linear para acessar cada elemento.
for idx = 1:numel(array) element = array(idx) .... end
Isso é útil se você não precisa saber em que i, j, k, você está. No entanto, se você não precisa saber em qual índice está, provavelmente será melhor usar arrayfun ()
fonte
I = cell(1, ndims(array)); [I{:}] = ind2sub(size(array),idx);
.A ideia de um índice linear para matrizes em matlab é importante. Um array no MATLAB é, na verdade, apenas um vetor de elementos, estendido na memória. O MATLAB permite que você use um índice de linha e coluna ou um único índice linear. Por exemplo,
A = magic(3) A = 8 1 6 3 5 7 4 9 2 A(2,3) ans = 7 A(8) ans = 7
Podemos ver a ordem em que os elementos são armazenados na memória, desenrolando o array em um vetor.
A(:) ans = 8 3 4 1 5 9 6 7 2
Como você pode ver, o 8º elemento é o número 7. Na verdade, a função find retorna seus resultados como um índice linear.
find(A>6) ans = 1 6 8
O resultado é que podemos acessar cada elemento por vez de uma matriz nd geral usando um único loop. Por exemplo, se quiséssemos elevar ao quadrado os elementos de A (sim, sei que existem maneiras melhores de fazer isso), poderíamos fazer isso:
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
Existem muitas circunstâncias em que o índice linear é mais útil. A conversão entre o índice linear e dois (ou mais) subscritos dimensionais é realizada com as funções sub2ind e ind2sub.
O índice linear se aplica em geral a qualquer array em matlab. Portanto, você pode usá-lo em estruturas, matrizes de células, etc. O único problema com o índice linear é quando eles ficam muito grandes. O MATLAB usa um número inteiro de 32 bits para armazenar esses índices. Portanto, se sua matriz tiver mais do que um total de 2 ^ 32 elementos, o índice linear falhará. É realmente apenas um problema se você usar matrizes esparsas com frequência, quando ocasionalmente isso pode causar um problema. (Embora eu não use uma versão do MATLAB de 64 bits, acredito que o problema foi resolvido para aqueles indivíduos sortudos que usam.)
fonte
x = ones(1,2^33,'uint8'); x(2^33)
funciona conforme o esperado.Conforme apontado em algumas outras respostas, você pode iterar sobre todos os elementos em uma matriz
A
(de qualquer dimensão) usando um índice linear de1
anumel(A)
em um único loop for. Existem também algumas funções que você pode usar:arrayfun
ecellfun
.Vamos primeiro supor que você tem uma função que deseja aplicar a cada elemento
A
(chamadomy_func
). Primeiro, você cria um identificador de função para esta função:Se
A
for uma matriz (do tipo double, single, etc.) de dimensão arbitrária, você pode usararrayfun
para aplicarmy_func
a cada elemento:Se
A
for uma matriz de células de dimensão arbitrária, você pode usarcellfun
para aplicarmy_func
a cada célula:outArgs = cellfun(fcn, A);
A função
my_func
deve ser aceitaA
como entrada. Se houver alguma saída demy_func
, ela será colocada emoutArgs
, que terá o mesmo tamanho / dimensão deA
.Uma advertência sobre saídas ... se
my_func
retorna saídas de diferentes tamanhos e tipos quando opera em diferentes elementos deA
, entãooutArgs
terá que ser transformado em uma matriz de células. Isso é feito chamando umarrayfun
oucellfun
com um par parâmetro / valor adicional:outArgs = arrayfun(fcn, A, 'UniformOutput', false); outArgs = cellfun(fcn, A, 'UniformOutput', false);
fonte
Um outro truque é usar
ind2sub
esub2ind
. Em conjunto comnumel
esize
, isso pode permitir que você faça coisas como o seguinte, que cria uma matriz N-dimensional e, em seguida, define todos os elementos na "diagonal" como 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
fonte
Você poderia fazer uma função recursiva fazer o trabalho
L = size(M)
idx = zeros(L,1)
length(L)
como profundidade máximafor idx(depth) = 1:L(depth)
length(L)
, faça a operação do elemento, senão chame a função novamente comdepth+1
Não tão rápido quanto os métodos vetorizados se você quiser verificar todos os pontos, mas se não precisar avaliar a maioria deles, pode economizar bastante tempo.
fonte
essas soluções são mais rápidas (cerca de 11%) do que usar
numel
;)for idx = reshape(array,1,[]), element = element + idx; end
ou
for idx = array(:)', element = element + idx; end
UPD. tnx @rayryeng para erro detectado na última resposta
aviso Legal
As informações de tempo referenciadas por esta postagem estão incorretas e imprecisas devido a um erro de digitação fundamental que foi cometido (veja o fluxo de comentários abaixo, bem como o histórico de edições - veja especificamente a primeira versão desta resposta). Caveat Emptor .
fonte
1 : array(:)
é equivalente a1 : array(1)
. Isso não itera por meio de todos os elementos, por isso seus tempos de execução são rápidos. Além disso,rand
gera números de ponto flutuante e , ao fazer1 : array(:)
isso, produziria uma matriz vazia, pois sua instrução está tentando encontrar um vetor crescente com seu valor inicial como 1 com um valor final como um número de ponto flutuante com um intervalo[0,1)
exclusivo de 1 em aumento passos de 1. Não existe tal vetor possível, o que resulta em um vetor vazio. Seufor
loop não funciona e, portanto, sua afirmação é falsa. -1 voto. Desculpe.reshape(...)
.1 : array(:)
no prompt de comando após criararray
. Você obteve uma matriz vazia? se sim, então seu código não funciona. Estou deixando meu voto porque você está dando informações falsas.Se você olhar mais profundamente para os outros usos de,
size
poderá ver que pode realmente obter um vetor do tamanho de cada dimensão. Este link mostra a documentação:www.mathworks.com/access/helpdesk/help/techdoc/ref/size.html
Depois de obter o vetor de tamanho, itere sobre esse vetor. Algo assim (perdoe minha sintaxe, já que não uso o Matlab desde a faculdade):
d = size(m); dims = ndims(m); for dimNumber = 1:dims for i = 1:d[dimNumber] ...
Transforme isso em sintaxe real Matlab-legal, e eu acho que faria o que você quiser.
Além disso, você deve ser capaz de fazer a indexação linear conforme descrito aqui .
fonte
Você deseja simular loops for aninhados.
A iteração por meio de uma matriz n-dimensional pode ser vista como um aumento do número de n dígitos.
Em cada dimensão temos tantos dígitos quanto o comprimento da dimensão.
Exemplo:
Suponha que tenhamos array (matriz)
int[][][] T=new int[3][4][5];
em "para notação" temos:
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]=...
para simular isso, você teria que usar a "notação numérica de n dígitos"
Temos um número de 3 dígitos, com 3 dígitos para o primeiro, 4 para o segundo e cinco para o terceiro dígito
Temos que aumentar o número, para obter a sequência
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
Portanto, você pode escrever o código para aumentar esse número de n dígitos. Você pode fazer isso de forma que possa começar com qualquer valor do número e aumentar / diminuir os dígitos em quaisquer números. Dessa forma, você pode simular loops for aninhados que começam em algum lugar da tabela e não terminam no final.
Porém, esta não é uma tarefa fácil. Não posso ajudar com a notação matlab, infelizmente.
fonte