2010-11-16 16 views
10

Chcę utworzyć n-wymiarową tablicę podwójną. Podczas kompilacji liczba wymiarów n nie jest znana.n-wymiarowa tablica

Doszedłem do zdefiniowania tablicy jako słownika, z kluczem będącym tablicą ints odpowiadającą różnym osiom (więc w 3-wymiarowej tablicy dostarczyłbym [5, 2, 3], aby uzyskać podwójnie przy (5, 2, 3) w tablicy

Jednak muszę również wypełnić słownik podwójnymi znakami od (0, 0, ... 0) do (m1, m2, ... mn) , gdzie m1 do mn jest długością każdej osi:

Moim początkowym pomysłem było utworzenie zagnieżdżonych pętli for, ale ponieważ wciąż nie wiem, ile potrzebuję (1 dla każdego wymiaru), mogę Zrobisz to podczas kompilacji

Ja ho Mam sformułowane pytanie w zrozumiały sposób, ale nie krępuj się poprosić mnie o opracowanie części.

+0

Jak korzystać z tablicy? –

+0

Zostanie użyty w obliczeniach losowych pola Markowa, gdzie mamy n warstw z m segmentami w każdym. Następnie chcemy stworzyć macierz prawdopodobieństw dla każdej zaobserwowanej wartości lub, w przypadku wartości ciągłych, dwie macierze dla średnich i wariancji dla każdej obserwowanej wartości. – SimonPip

Odpowiedz

6

szybkie nawiązanie w tym zakresie:

Użyliśmy metody Array.CreateInstance z powodzeniem, ale jak ktoś przewidywał, była ona dość nieefektywna i dodatkowo powodowała problemy z czytelnością.

Zamiast tego opracowaliśmy metodę, w której tablica n-wymiarowa jest przekształcana w tablicę jednowymiarową (normalną).

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

Jest to zasadniczo uogólnienie dotyczące konwersji współrzędnych kartezjańskich na jedną liczbę całkowitą iz powrotem.

Nasze testy nie są sformalizowane, więc każde przyspieszenie, które uzyskaliśmy, jest całkowicie anegdotyczne, ale dla mojej maszyny przyspieszyło o 30-50%, w zależności od wielkości próbki, a czytelność kodu poprawiła się przez szeroki margines.

Mam nadzieję, że pomoże to każdemu, kto natknie się na to pytanie.

0

Dlaczego po prostu nie użyjesz tablicy wielowymiarowej: double[,,] array = new double[a,b,c]? Wszystkie elementy tablicy są automatycznie inicjowane do wartości 0.0 dla Ciebie.

Alternatywnie, można użyć tablicę double[][][] poszarpane, ale każdy sub-array będą musiały być inicjowane w for pętli:

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: Nie wiedziałem, że liczba wymiarów została run-time. Dodano inną odpowiedź powyżej.

+1

Ponieważ nie znam liczby wymiarów podczas kompilacji.Przepraszamy, jeśli przykład (5, 2, 3) Cię pomylił. Równie dobrze mogło to być (5, 3, 2, 8, 7, 6, 32). :) – SimonPip

15

Aby utworzyć macierz n-wymiarowej, można użyć metodę 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); 

do wypełnienia macierzy, można skorzystać z właściwości Rank i GetLength aby zwrócić długości bieżącej wymiar, z zastosowaniem kilka zagnieżdżonej pętli zrobić o (n^m) algo (uwaga - przetestowane)

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