2010-11-16 17 views
10

Quiero crear una matriz n-dimensional de dobles. En tiempo de compilación, se desconoce el número de dimensiones n.n-dimensional Array

Terminé definiendo la matriz como un diccionario, con la clave siendo una matriz de entradas correspondiente a los diferentes ejes (así que en una matriz tridimensional, proporcionaría [5, 2, 3] para obtener la doble en (5, 2, 3) en la matriz

Sin embargo, también necesito llenar el diccionario con dobles de (0, 0, ... 0) a (m1, m2, ... mn) , donde m1 a mn es la longitud de cada eje.

Mi idea inicial era crear bucles foráneos anidados, pero como aún no sé cuántos necesitaría (1 para cada dimensión), puedo no hacer esto en tiempo de compilación.

I ho pe Formulé la pregunta de una manera comprensible, pero siéntanse libres de pedirme que explique las partes.

+0

¿Cómo se usará la matriz? –

+0

Se usará en los cálculos de campo aleatorio de Factorial Markov, donde tenemos n capas con m segmentos en cada una. Luego queremos hacer una matriz de probabilidades para cada valor observado, o en el caso de valores continuos, dos matrices, para medias y varianza, para cada valor observado. – SimonPip

Respuesta

6

un seguimiento rápido en este asunto:

Utilizamos el método Array.CreateInstance con éxito, pero, como alguien predijo, era bastante ineficiente y, además, creaba problemas de legibilidad.

En su lugar, hemos desarrollado un método, donde la matriz n-dimensional se convierte en una matriz unidimensional (normal).

public static int NDToOneD(int[] indices, int[] lengths) 
{ 
    int ID = 0; 
    for (int i = 0; i < indices.Length; i++) 
    { 
    int offset = 1; 
    for (int j = 0; j < i; j++) 
{ 
     offset *= lengths[j]; 
} 
    ID += indices[i] * offset; 
    } 
    return ID; 
} 

1DtoND(int[] indices, int[] arrayLengths) 
{ 
    int[] indices = new int[lengths.Length]; 
    for (int i = lengths.Length - 1; i >= 0; i--) 
    { 
    int offset = 1; 
    for (int j = 0; j < i; j++) 
    { 
     offset *= lengths[j]; 
    } 
    int remainder = ID % offset; 
    indices[i] = (ID - remainder)/offset; 
    ID = remainder; 
    } 
    return indices; 
} 

Esto es esencialmente una generalización sobre la conversión de coordenadas cartesianas a un solo entero y viceversa.

Nuestras pruebas no están formalizadas, por lo que cualquier aceleración que hayamos obtenido es completamente anecdótica, pero para mi máquina, ha dado una aceleración de 30-50%, dependiendo del tamaño de muestra, y la legibilidad del código ha mejorado por un amplio margen.

Espero que esto ayude a cualquiera que tropiece con esta pregunta.

0

¿Por qué no solo utiliza una matriz multidimensional: double[,,] array = new double[a,b,c]? Todos los elementos de la matriz se inicializan automáticamente a 0.0 para usted.

Alternativamente, se puede utilizar una matriz escalonada double[][][], pero tendrá que ser inicializado en un bucle for cada sub-serie:

int a, b, c; 
double[][][] array = new double[a][][]; 

for (int i=0; i<a; i++) { 
    double[i] = new double[b][]; 

    for (int j=0; j<b; j++) { 
     double[i][j] = new double[c]; 
    } 
} 

EDIT: no se dio cuenta varias dimensiones se llevó a cabo a tiempo. Se agregó otra respuesta arriba.

+1

Porque no sé la cantidad de dimensiones en tiempo de compilación.Lo siento, si el ejemplo (5, 2, 3) te confundió. Podría haber sido (5, 3, 2, 8, 7, 6, 32). :) – SimonPip

15

Para crear una matriz n-dimensional, se puede utilizar el Array.CreateInstance método:

Array array = Array.CreateInstance(typeof(double), 5, 3, 2, 8, 7, 32)); 

array.SetValue(0.5d, 0, 0, 0, 0, 0, 0); 
double val1 = (double)array.GetValue(0, 0, 0, 0, 0, 0); 

array.SetValue(1.5d, 1, 2, 1, 6, 0, 30); 
double val2 = (double)array.GetValue(1, 2, 1, 6, 0, 30); 

Para rellenar las matrices, se puede utilizar la propiedad Rank y GetLength método para devolver la longitud de la dimensión actual, utilizando un par de bucles for anidados para hacer un O (n^m) algo (advertencia - no probado):

private bool Increment(Array array, int[] idxs, int dim) { 
    if (dim >= array.Rank) return false; 

    if (++idxs[idxs.Length-dim-1] == array.GetLength(dim)) { 
     idxs[idxs.Length-dim-1] = 0; 
     return Increment(array, idxs, dim+1); 
    } 
    return true; 
} 

Array array = Array.CreateInstance(typeof(double), ...); 
int[] idxs = new int[array.Rank]; 
while (Increment(array, idxs, 0)) { 
    array.SetValue(1d, idxs); 
}