2010-11-16 14 views
10

Voglio creare una matrice n-dimensionale di doppi. Al momento della compilazione, il numero di dimensioni n non è noto.Array n-dimensionale

Ho finito per definire l'array come un dizionario, con la chiave costituita da una matrice di ints corrispondente ai diversi assi (quindi in un array tridimensionale, fornirei [5, 2, 3] per ottenere il doppio a (5, 2, 3) nell'array

Tuttavia, ho anche bisogno di popolare il dizionario con i doppi da (0, 0, ... 0) a (m1, m2, ... mn) , dove m1 in mn è la lunghezza di ciascun asse

La mia idea iniziale era di creare cicli forati annidati, ma poiché non so ancora quanti ne avrei bisogno (1 per ogni dimensione), posso lo faccio al momento della compilazione

I ho pe Ho formulato la domanda in modo comprensibile, ma non esitare a chiedermi di elaborare parti.

+0

Come verrà utilizzato l'array? –

+0

Verrà utilizzato nei calcoli del campo casuale Markov di tipo Factorial, in cui sono presenti n strati con m segmenti ciascuno. Vogliamo quindi creare una matrice di probabilità per ogni valore osservato, o nel caso di valori continui, due matrici, per medie e varianze, per ciascun valore osservato. – SimonPip

risposta

6

un rapido follow-up su questo argomento:

Abbiamo utilizzato il metodo Array.CreateInstance con esito positivo, ma come previsto da qualcuno, era piuttosto inefficiente e inoltre ha creato problemi di leggibilità.

Invece, abbiamo sviluppato un metodo, in cui l'array n-dimensionale viene convertito in un array 1-dimensionale (normale).

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; 
} 

Questa è essenzialmente una generalizzazione sulla conversione di coordinate cartesiane su un singolo intero e viceversa.

Il nostro test non è formalizzato, quindi qualsiasi accelerazione che abbiamo ottenuto è del tutto aneddotico, ma per la mia macchina ha dato un aumento del 30-50%, a seconda delle dimensioni del campione, e la leggibilità del codice è migliorata con un ampio margine.

Spero che questo aiuti chiunque si imbatta in questa domanda.

0

Perché non si utilizza solo un array multidimensionale: double[,,] array = new double[a,b,c]? Tutti gli elementi dell'array vengono automaticamente inizializzati a 0.0 per te.

In alternativa, è possibile utilizzare una matrice irregolare double[][][], ma sarà necessario essere inizializzato in un ciclo for ogni sub-array:

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: non realizzò numero di dimensioni è stato eseguito in tempo. Aggiunta un'altra risposta sopra.

+1

Perché non conosco il numero di dimensioni in fase di compilazione.Spiacente, se l'esempio (5, 2, 3) ti ha confuso. Potrebbe anche essere stato (5, 3, 2, 8, 7, 6, 32). :) – SimonPip

15

Per creare un array n-dimensionale, è possibile utilizzare il metodo Array.CreateInstance:

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); 

Per popolare gli array, è possibile utilizzare la proprietà Rank e GetLength metodo per restituire la lunghezza della dimensione corrente, utilizzando un paio di cicli for innestati per fare una O (n^m) algo (avviso - non testata):

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); 
}