2010-11-16 5 views
10

Ich möchte ein n-dimensionales Array von Doubles erstellen. Zur Kompilierungszeit ist die Anzahl der Dimensionen n nicht bekannt.n-dimensionales Array

Ich definierte das Array schließlich als Wörterbuch, wobei der Schlüssel ein Array von Ints war, die den verschiedenen Achsen entsprachen (also würde ich in einem 3-dimensionalen Array [5, 2, 3] liefern) doppelt bei (5, 2, 3) im Array

Allerdings muss ich auch das Wörterbuch mit Doppel von (0, 0, ... 0) bis (m1, m2, ... mn) bevölkern , wobei m1 bis mn die Länge jeder Achse ist

Meine ursprüngliche Idee war es, verschachtelte for-Schleifen zu erstellen, aber da ich immer noch nicht weiß, wie viele ich brauchen würde (1 für jede Dimension), kann ich tu dies zur Kompilierzeit

ich ho Ich habe die Frage verständlich formuliert, aber bitte frag mich, ob ich Teile ausarbeiten soll.

+0

Wie wird das Array verwendet? –

+0

Es wird in der Random-Field-Markov-Random Field-Berechnung verwendet, wo wir n Schichten mit m Segmenten in jedem haben. Wir wollen dann eine Matrix von Wahrscheinlichkeiten für jeden beobachteten Wert oder, im Fall von kontinuierlichen Werten, zwei Matrizen für Mittel und Varianz für jeden beobachteten Wert machen. – SimonPip

Antwort

6

eine schnelle followup zu diesem Thema:

Wir haben die Array.CreateInstance-Methode mit Erfolg verwendet, aber wie jemand vorausgesagt hat, war sie ziemlich ineffizient und verursachte Lesbarkeitsprobleme.

Stattdessen haben wir eine Methode entwickelt, bei der das n-dimensionale Array in ein 1-dimensionales (normales) Array konvertiert wird.

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

Dies ist im Wesentlichen eine Verallgemeinerung bei der Umwandlung von kartesischen Koordinaten in eine einzelne ganze Zahl und wieder zurück.

Unsere Tests sind nicht formalisiert, daher ist jede Beschleunigung, die wir erzielt haben, völlig anekdotisch, aber für meine Maschine hat sie je nach Stichprobenumfang eine 30-50% ige Beschleunigung ergeben und die Lesbarkeit des Codes hat sich verbessert mit großem Abstand.

Hoffe das hilft jedem, der auf diese Frage stolpert.

0

Warum verwenden Sie nicht einfach ein mehrdimensionales Array: double[,,] array = new double[a,b,c]? Alle Array-Elemente werden automatisch für Sie auf 0.0 initialisiert.

Alternativ können Sie eine gezackte Array verwenden double[][][], aber jedes Sub-Array müssen in einer for Schleife initialisiert werden:

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: war nicht klar, Anzahl der Dimensionen Laufzeit wurde. Oben eine andere Antwort hinzugefügt.

+1

Weil ich die Anzahl der Dimensionen zur Kompilierzeit nicht kenne.Entschuldigung, wenn dich das (5, 2, 3) Beispiel verwirrt hat. Es hätte genauso gut sein können (5, 3, 2, 8, 7, 6, 32). :) – SimonPip

15

Um einen n-dimensionalen Array zu erstellen, können Sie die Array.CreateInstance Methode verwenden:

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

die Arrays So zu füllen, können Sie die Rank Eigenschaft und GetLength Methode verwenden, um die Länge der aktuellen Dimension zurückzukehren, verwenden ein paar verschachtelten for-Schleifen ein O (n^m) algo (Warnung - nicht getestet) zu tun:

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