Tengo un problema. Necesito iterar a través de cada elemento en una matriz n-dimensional en MATLAB. El problema es que no sé cómo hacer esto para un número arbitrario de dimensiones. Se que puedo decir
for i = 1:size(m,1)
for j = 1:size(m,2)
for k = 1:size(m,3)
y así sucesivamente, pero ¿hay alguna manera de hacerlo para un número arbitrario de dimensiones?
Respuestas:
Puede utilizar la indexación lineal para acceder a cada elemento.
for idx = 1:numel(array) element = array(idx) .... end
Esto es útil si no necesita saber en qué se encuentra i, j, k. Sin embargo, si no necesita saber en qué índice se encuentra, probablemente sea mejor que use arrayfun ()
fuente
I = cell(1, ndims(array)); [I{:}] = ind2sub(size(array),idx);
.La idea de un índice lineal para matrices en matlab es importante. Una matriz en MATLAB es en realidad solo un vector de elementos, encadenados en la memoria. MATLAB le permite utilizar un índice de fila y columna, o un índice lineal único. Por ejemplo,
A = magic(3) A = 8 1 6 3 5 7 4 9 2 A(2,3) ans = 7 A(8) ans = 7
Podemos ver el orden en que se almacenan los elementos en la memoria desenrollando la matriz en un vector.
A(:) ans = 8 3 4 1 5 9 6 7 2
Como puede ver, el octavo elemento es el número 7. De hecho, la función encontrar devuelve sus resultados como un índice lineal.
find(A>6) ans = 1 6 8
El resultado es que podemos acceder a cada elemento a su vez de una matriz nd general utilizando un solo ciclo. Por ejemplo, si quisiéramos cuadrar los elementos de A (sí, sé que hay mejores formas de hacerlo), uno podría hacer esto:
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
Hay muchas circunstancias en las que el índice lineal es más útil. La conversión entre el índice lineal y subíndices de dos (o más) dimensiones se logra con las funciones sub2ind e ind2sub.
El índice lineal se aplica en general a cualquier matriz en matlab. Entonces puede usarlo en estructuras, matrices de celdas, etc. El único problema con el índice lineal es cuando se vuelven demasiado grandes. MATLAB utiliza un entero de 32 bits para almacenar estos índices. Entonces, si su matriz tiene más de un total de 2 ^ 32 elementos, el índice lineal fallará. En realidad, solo es un problema si usa matrices dispersas con frecuencia, cuando ocasionalmente esto causará un problema. (Aunque no uso una versión de MATLAB de 64 bits, creo que ese problema se ha resuelto para los afortunados que lo hacen).
fuente
x = ones(1,2^33,'uint8'); x(2^33)
funciona como se esperaba.Como se señaló en algunas otras respuestas, puede iterar sobre todos los elementos en una matriz
A
(de cualquier dimensión) usando un índice lineal de1
anumel(A)
en un solo bucle for. También hay un par de funciones que puede utilizar:arrayfun
ycellfun
.Primero supongamos que tiene una función que desea aplicar a cada elemento de
A
(llamadomy_func
). Primero crea un identificador de función para esta función:Si
A
es una matriz (de tipo doble, simple, etc.) de dimensión arbitraria, puede usararrayfun
para aplicarmy_func
a cada elemento:Si
A
es una matriz de celdas de dimensión arbitraria, puede usarcellfun
para aplicarmy_func
a cada celda:outArgs = cellfun(fcn, A);
La función
my_func
tiene que aceptarA
como entrada. Si hay alguna salida demy_func
, se colocan enoutArgs
, que será del mismo tamaño / dimensión queA
.Una advertencia sobre las salidas ... si
my_func
devuelve salidas de diferentes tamaños y tipos cuando opera en diferentes elementos deA
, entoncesoutArgs
tendrá que convertirse en una matriz de celdas. Esto se hace llamando aarrayfun
ocellfun
con un par de parámetro / valor adicional:outArgs = arrayfun(fcn, A, 'UniformOutput', false); outArgs = cellfun(fcn, A, 'UniformOutput', false);
fuente
Otro truco consiste en utilizar
ind2sub
ysub2ind
. Junto connumel
ysize
, esto puede permitirle hacer cosas como las siguientes, que crean una matriz N-dimensional, y luego establece todos los elementos en la "diagonal" en 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
fuente
Podrías hacer que una función recursiva haga el trabajo
L = size(M)
idx = zeros(L,1)
length(L)
como profundidad máximafor idx(depth) = 1:L(depth)
length(L)
, realice la operación del elemento, de lo contrario, llame a la función nuevamente condepth+1
No es tan rápido como los métodos vectorizados si desea verificar todos los puntos, pero si no necesita evaluar la mayoría de ellos, puede ahorrar bastante tiempo.
fuente
estas soluciones son más rápidas (alrededor del 11%) que usar
numel
;)for idx = reshape(array,1,[]), element = element + idx; end
o
for idx = array(:)', element = element + idx; end
UPD. tnx @rayryeng por error detectado en la última respuesta
Descargo de responsabilidad
La información de tiempo a la que se ha hecho referencia en esta publicación es incorrecta e inexacta debido a un error tipográfico fundamental que se cometió (consulte el flujo de comentarios a continuación, así como el historial de edición ; mire específicamente la primera versión de esta respuesta). Caveat Emptor .
fuente
1 : array(:)
es equivalente a1 : array(1)
. Esto no itera a través de todos los elementos, por lo que sus tiempos de ejecución son rápidos. Además,rand
genera números de punto flotante , y al hacerlo1 : array(:)
produciría una matriz vacía ya que su declaración está tratando de encontrar un vector creciente con su valor inicial como 1 con un valor final como un número de punto flotante con un rango de[0,1)
exclusivo de 1 en aumento pasos de 1. No existe tal vector posible, lo que resulta en un vector vacío. Sufor
ciclo no se ejecuta, por lo que su afirmación es falsa. -1 voto. lo siento.reshape(...)
.1 : array(:)
en el símbolo del sistema después de creararray
. ¿Obtienes una matriz vacía? si es así, entonces su código no funciona. Dejo mi voto porque está dando información falsa.Si observa más a fondo los otros usos de
size
, puede ver que en realidad puede obtener un vector del tamaño de cada dimensión. Este enlace le muestra la documentación:www.mathworks.com/access/helpdesk/help/techdoc/ref/size.html
Después de obtener el vector de tamaño, itere sobre ese vector. Algo como esto (perdón por mi sintaxis ya que no he usado Matlab desde la universidad):
d = size(m); dims = ndims(m); for dimNumber = 1:dims for i = 1:d[dimNumber] ...
Convierta esto en una sintaxis legal de Matlab real, y creo que haría lo que quiera.
Además, debería poder realizar la indexación lineal como se describe aquí .
fuente
Quiere simular bucles for anidados n.
La iteración a través de una matriz n-dimmensional puede verse como un aumento del número de n dígitos.
En cada dimmension tenemos tantos dígitos como la longitud de la dimmension.
Ejemplo:
Supongamos que tenemos una matriz (matriz)
int[][][] T=new int[3][4][5];
en "para notación" tenemos:
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 esto, tendría que utilizar la "notación numérica de n dígitos"
Tenemos un número de 3 dígitos, con 3 dígitos para el primero, 4 para el segundo y cinco para el tercer dígito
Tenemos que aumentar el número, así obtendríamos la secuencia
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
Entonces puede escribir el código para aumentar ese número de n dígitos. Puede hacerlo de tal manera que pueda comenzar con cualquier valor del número y aumentar / disminuir los dígitos en cualquier número. De esa manera, puede simular bucles for anidados que comienzan en algún lugar de la tabla y no terminan al final.
Sin embargo, esta no es una tarea fácil. Desafortunadamente, no puedo ayudar con la notación matlab.
fuente