n-dimensional Array

A quick followup on this matter:

We used the Array.CreateInstance method with success, but as someone predicted, it was fairly inefficient, and additionally created readability problems.

Instead, we have developed a method, where the n-dimensional array is converted into a 1-dimensional (normal) array.

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

This is essentially a generalisation on the conversion of cartesian coordinates to a single integer and back again.

Our testing is not formalized, so any speedup we have gained is entirely anecdotal, but for my machine, it has given about a 30-50% speedup, depending on the sample size, and the readability of the code has improved by a wide margin.

Hope this helps anyone who stumbles upon this question.


To create a n-dimensional array, you can use the Array.CreateInstance method:

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

To populate the arrays, you can use the Rank property and GetLength method to return the length of the current dimension, using a couple of nested for loops to do a O(n^m) algo (warning - untested):

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