【问题标题】:n-dimensional Arrayn 维数组
【发布时间】:2011-05-10 18:09:12
【问题描述】:

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

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

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

我最初的想法是创建嵌套的 for 循环,但由于我仍然不知道需要多少个(每个维度 1 个),所以我无法在编译时执行此操作。

我希望我以一种可以理解的方式提出了这个问题,但请随时要求我详细说明部分。

【问题讨论】:

  • 它将用于阶乘马尔可夫随机场计算,其中我们有 n 层,每层有 m 个段。然后,我们想要为每个观察值创建一个概率矩阵,或者在连续值的情况下,为每个观察值创建两个矩阵,用于均值和方差。

标签: c# arrays multidimensional-array


【解决方案1】:

要创建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);

要填充数组,您可以使用 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);
}

【讨论】:

    【解决方案2】:

    关于此事的快速跟进:

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

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

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

    这本质上是关于将笛卡尔坐标转换为单个整数然后再转换回来的概括。

    我们的测试没有正式化,所以我们获得的任何加速都完全是传闻,但对于我的机器,它提供了大约 30-50% 的加速,具体取决于样本大小,并且代码的可读性提高了很大的余量。

    希望这对偶然发现这个问题的人有所帮助。

    【讨论】:

      【解决方案3】:

      为什么不直接使用多维数组: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];
          }
      }
      

      编辑:没有意识到维数是运行时的。在上面添加了另一个答案。

      【讨论】:

      • 因为我不知道编译时的维数。抱歉,如果 (5, 2, 3) 示例让您感到困惑。也可能是 (5, 3, 2, 8, 7, 6, 32)。 :)
      • @thecoop 我认为可以删除此答案是否正确?
      【解决方案4】:

      使用此方法,您可以创建任意类型的 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;
          }
      

      【讨论】:

        猜你喜欢
        • 2016-05-28
        • 2011-06-13
        • 1970-01-01
        • 1970-01-01
        • 2016-07-02
        • 1970-01-01
        • 1970-01-01
        • 2013-04-03
        • 2011-06-14
        相关资源
        最近更新 更多