简体   繁体   English

n维数组

[英]n-dimensional Array

I want to create an n-dimensional array of doubles. 我想创建一个n维的双精度数组。 At compile-time, the number of dimensions n is not known. 在编译时,维数n的数量是未知的。

I ended up defining the array as a dictionary, with the key being an array of ints corresponding to the different axes (so in a 3-dimensional array, I'd supply [5, 2, 3] to get the double at (5, 2, 3) in the array. 我最后将数组定义为字典,键是一个对应于不同轴的int数组(所以在三维数组中,我提供[5,2,3]得到双精度(5 ,2,3)在数组中。

However, I also need to populate the dictionary with doubles from (0, 0, ... 0) to (m1, m2, ... mn), where m1 to mn is the length of each axis. 但是,我还需要使用从(0,0,... 0)到(m1,m2,... mn)的双精度填充字典,其中m1到mn是每个轴的长度。

My initial idea was to create nested for-loops, but as I still don't know how many I'd need (1 for each dimension), I can't do this at compile-time. 我最初的想法是创建嵌套的for循环,但由于我仍然不知道我需要多少(每个维度1个),所以我无法在编译时执行此操作。

I hope I've formulated the question in an understandable manner, but feel free to ask me to elaborate parts. 我希望我以一种可以理解的方式提出问题,但请随时让我详细说明部分内容。

To create a n-dimensional array, you can use the Array.CreateInstance method: 要创建n维数组,可以使用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);

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): 要填充数组,可以使用Rank属性和GetLength方法返回当前维度的长度,使用几个嵌套for循环来执行O(n ^ m)算法(警告 - 未经测试):

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

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. 我们成功使用了Array.CreateInstance方法,但正如有人预测的那样,效率相当低,并且还会产生可读性问题。

Instead, we have developed a method, where the n-dimensional array is converted into a 1-dimensional (normal) array. 相反,我们开发了一种方法,其中n维数组被转换为1维(正常)数组。

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. 我们的测试没有正式化,所以我们获得的任何加速都完全是轶事,但对于我的机器,它提供了大约30-50%的加速,具体取决于样本大小,并且代码的可读性大大提高了。

Hope this helps anyone who stumbles upon this question. 希望这可以帮助任何偶然发现这个问题的人。

Why don't you just use a multidimensional array: double[,,] array = new double[a,b,c] ? 你为什么不使用多维数组: double[,,] array = new double[a,b,c] All the array elements are automatically initialized to 0.0 for you. 所有数组元素都会自动初始化为0.0。

Alternatively, you could use a jagged array double[][][] , but each sub-array will need to be initialized in a for loop: 或者,您可以使用锯齿状数组double[][][] ,但每个子数组都需要在for循环中初始化:

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: didn't realise number of dimensions was run-time. 编辑:没有意识到维度的数量是运行时。 Added another answer above. 上面添加了另一个答案

With this method, you can create n-dimensional jagged arrays of any type. 使用此方法,您可以创建任何类型的n维锯齿状数组。

    public static Array CreateJaggedArray<T>(params int[] lengths)
    {
        if(lengths.Length < 1)
            throw new ArgumentOutOfRangeException(nameof(lengths));

        void Populate(Array array,  int index)
        {
            for (int i = 0; i < array.Length; i++)
            {
                Array element = (Array)Activator.CreateInstance(array.GetType().GetElementType(), lengths[index]);
                array.SetValue(element, i);
                if (index + 1 < lengths.Length)
                    Populate(element, index + 1);

            }
        }

        Type retType = typeof(T);
        for (var i = 0; i < lengths.Length; i++)
            retType = retType.MakeArrayType();

        Array ret = (Array)Activator.CreateInstance(retType, lengths[0]);
        if (lengths.Length > 1)
            Populate(ret, 1);
        return ret;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM