C# n维阵列

C# n维阵列,c#,arrays,multidimensional-array,C#,Arrays,Multidimensional Array,我想创建一个n维的双精度数组。在编译时,维数n是未知的 我最终将数组定义为一个字典,其中键是一个对应于不同轴的整数数组(因此在三维数组中,我将提供[5,2,3],以获得数组中(5,2,3)处的双精度 但是,我还需要用从(0,0,…0)到(m1,m2,…mn)的双精度数字填充字典,其中m1到mn是每个轴的长度 我最初的想法是为循环创建嵌套,但我仍然不知道需要多少(每个维度1个),所以我不能在编译时这样做 我希望我已经以一种可以理解的方式阐述了这个问题,但请随意让我详细说明各个部分。为什么不使用多维

我想创建一个n维的双精度数组。在编译时,维数n是未知的

我最终将数组定义为一个字典,其中键是一个对应于不同轴的整数数组(因此在三维数组中,我将提供[5,2,3],以获得数组中(5,2,3)处的双精度

但是,我还需要用从(0,0,…0)到(m1,m2,…mn)的双精度数字填充字典,其中m1到mn是每个轴的长度

我最初的想法是为循环创建嵌套,但我仍然不知道需要多少(每个维度1个),所以我不能在编译时这样做


我希望我已经以一种可以理解的方式阐述了这个问题,但请随意让我详细说明各个部分。

为什么不使用多维数组:
double[,]array=new double[a,b,c]
?所有数组元素都会自动初始化为0.0

或者,您可以使用锯齿状数组
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];
    }
}
inta、b、c;
双精度[][]阵列=新的双精度[a][];

对于(int i=0;i要创建n维数组,可以使用以下方法:

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


对此问题的快速跟进:

我们成功地使用了Array.CreateInstance方法,但正如有人预测的那样,它效率相当低,并且还造成了可读性问题

相反,我们开发了一种方法,将n维数组转换为一维(法线)数组

公共静态int ndtoone(int[]索引,int[]长度)
{
int ID=0;
for(int i=0;i=0;i--)
{
int offset=1;
对于(int j=0;j
这本质上是一个将笛卡尔坐标转换为单个整数再转换回来的推广

我们的测试还没有正式化,所以我们获得的任何加速都是轶事,但对于我的机器来说,它提供了大约30-50%的加速,这取决于样本大小,并且代码的可读性大大提高


希望这能帮助任何偶然发现这个问题的人。

使用此方法,您可以创建任意类型的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;
    }
公共静态数组CreateJaggedArray(参数int[]长度)
{
如果(长度。长度<1)
抛出新ArgumentOutOfRangeException(nameof(length));
无效填充(数组、整数索引)
{
for(int i=0;i1)
填充(ret,1);
返回ret;
}

因为我不知道编译时的维度数。抱歉,如果(5,2,3)示例让您感到困惑,那么它可能是(5,3,2,8,7,6,32)。:)它将用于阶乘马尔可夫随机场计算,其中我们有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);
}
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;
}
    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;
    }