【问题标题】:How to get cross section of 3 dimensional array c#如何获得3维数组c#的横截面
【发布时间】:2017-04-07 07:40:13
【问题描述】:

假设你在 c# 中有一个 3 维数组

int space[width, height, depth];

你想实现这个方法

public int[,] GetCrossSection(int position, int dimension)

其中“位置”是沿“维度”指定的点,您要在其中提取切片。 使用我们仅处理 3 维这一事实很重要,在下面的示例中,您可以通过添加 if 语句来修复它们,并假设矩阵不会超过 3 维。

我的第一次尝试(评论了问题领域):

public int[,] GetCrossSection(int position, int dimension)
{
    int[] dimensionIterationInterval = new int[] { width, height, depth };
    var dims = new List<int>(dimensionIterationInterval);
    dims.RemoveAt(dimension);
    dimensionIterationInterval = dims.ToArray();


    int[,] crossSection = new int[dimensionIterationInterval[0], dimensionIterationInterval[1]];
    int[] itr = new int[2];
    for (itr[0] = 0; itr[0] < dimensionIterationInterval[0]; itr[0]++)
    {
        for (itr[1] = 0; itr[1] < dimensionIterationInterval[1]; itr[1]++)
        {
           crossSection[itr[0], itr[1]] = space[?,?,?]; //Problem
        }
     }
}

而我的第二次尝试同样徒劳:

public int[,] GetCrossSection(int position, int dimension)
{
    int[,] dimensionIterationInterval = new int[,] { { 0, width }, { 0, height }, { 0, depth } };
    dimensionIterationInterval[dimension, 0] = position;
    dimensionIterationInterval[dimension, 1] = position + 1;

    int[,] crossSection = new int[?,?]; //Problem
    for (int x = dimensionIterationInterval[0, 0]; x < dimensionIterationInterval[0, 1]; x++)
     {
       for (int y = dimensionIterationInterval[1, 0]; y< dimensionIterationInterval[1, 1]; y++)
        {
          for (int z = dimensionIterationInterval[2, 0]; z < dimensionIterationInterval[2, 1]; z++)
          {
              crossSection[?, ?] = space[x, y, z]; // Problem
          }
         }
      }
 }

这两种尝试都陷入了死胡同。你会怎么解决?对于空间[,,]的维数有固定的迭代循环是可以的。如果维度的数量增加,这在某种程度上是可以控制的。聪明/有限的 if 语句可以工作,但对于每个维度都没有过多的 ifs。

【问题讨论】:

  • 感谢聪明的语言特定的东西,但我也对“伪代码”之类的问题感兴趣,如果有一些结构可以用来解决我发现的问题我的两次尝试。

标签: c# arrays multidimensional-array


【解决方案1】:

快速草稿:

    static int[,] GetSlice(int[,,] source, int dimension, int position)
    {
        int l1 = 0, l2 = 0;
        if (dimension == 0)
        {
            l1 = source.GetLength(1);
            l2 = source.GetLength(2);
        }
        else if (dimension == 1)
        {
            l1 = source.GetLength(0);
            l2 = source.GetLength(2);
        }
        else if (dimension == 2)
        {
            l1 = source.GetLength(0);
            l2 = source.GetLength(1);
        }

        var result = new int[l1, l2];

        var s0 = dimension == 0 ? position : 0;
        var s1 = dimension == 1 ? position : 0;
        var s2 = dimension == 2 ? position : 0;

        var m0 = dimension == 0 ? position + 1 : source.GetLength(0);
        var m1 = dimension == 1 ? position + 1 : source.GetLength(1);
        var m2 = dimension == 2 ? position + 1 : source.GetLength(2);

        for (var i0 = s0; i0 < m0; i0++)
        for (var i1 = s1; i1 < m1; i1++)
        for (var i2 = s2; i2 < m2; i2++)
        {
            int x = 0, y = 0;
            if (dimension == 0)
            {
                x = i1;
                y = i2;
            }
            else if (dimension == 1)
            {
                x = i0;
                y = i2;
            }
            else if (dimension == 2)
            {
                x = i0;
                y = i1;
            }

            result[x, y] = source[i0, i1, i2];
        }

        return result;
    }

它可以推广到任意数量的维度(甚至可以使代码更小更简单)。

【讨论】:

    【解决方案2】:

    没有调试它,但猜它应该可以工作

     private int[,,] _space = new int[width, height, depth];
    
        public int[,] GetCrossSection(int position, int dimension)
        {
            if (dimension < 0 || dimension > 2) return null;
            if (position > _space.GetLength(dimension) || position < 0) return null;
            var minMax = new Tuple<int, int>[3];
            var resultXLength = -1;
            var resultYLength = -1;
            for (var i = 0; i < _space.Rank; i++)
            {
                if (i == dimension)
                {
                    minMax[i] = new Tuple<int, int>(position, position+1);
                }
                else
                {
                    minMax[i] = new Tuple<int, int>(0,_space.GetLength(i));
                    if (resultXLength == -1) resultXLength = _space.GetLength(i);
                    else resultYLength = _space.GetLength(i);
                }
            }
            var result = new int[resultXLength, resultYLength];
            for (var i = minMax[0].Item1; i < minMax[0].Item2; i++)
                for (var j = minMax[1].Item1; j < minMax[1].Item2; j++)
                    for (var k = minMax[2].Item1; k < minMax[2].Item2; k++)
                    {
                        switch (dimension)
                        {
                            case 0:
                            {
                                result[j, k] = _space[i, j, k];
                                break;
                            }
                            case 1:
                            {
                                result[i, k] = _space[i, j, k];
                                break;
                            }
                            case 2:
                            {
                                result[i, j] = _space[i, j, k];
                                break;
                            }
                        }
                    }
            return result;
        }
    

    【讨论】:

      【解决方案3】:

      在做了几个星期的其他事情之后,在稍微弄乱了 Mykola 的回答之后,我得出了:

      int[,] GetSlice(int[,,] source /*non dynamic 1*/, int dimension, int position)
      {
          int dimensions = source.Rank; 
          int[] dims = new int[dimensions-1];
      
          for(int j = 0; j < dims.Length; j++){
              dims[j] = source.GetLength(j + (j >= dimension ? 1 :0));
          }
      
          var result = new int[dims[0], dims[1]]; // non dynamic 2
      
          int[] start = new int[dimensions];
          int[] end = new int[dimensions];
          for(int i = 0; i < dimensions; i++){
              start[i] = dimension == i ? position : 0;
              end[i] = dimension == i ? position + 1 : source.GetLength(i);
          }
      
          int[] counters = new int[dimensions];
          for (counters[0] = start[0]; counters[0] < end[0]; counters[0]++)
          for (counters[1] = start[1]; counters[1] < end[1]; counters[1]++)
          for (counters[2] = start[2]; counters[2] < end[2]; counters[2]++) // non dynamic 3
          {
              int[] sliceCoord = new int[dimensions-1];
      
              for(int i = 0; i < t.Length; i++){
                  sliceCoord[i] = counters[i + (i >= dimension ? 1 :0)];
              }
      
              result[sliceCoord[0], sliceCoord[1]] = source[counters[0], counters[1], counters[2]]; // non dynamic 4
          }
      
          return result;
      }
      

      结论:如果您不希望这种动态行为,数组不是执行此操作的数据结构。

      上面的代码有点像我写问题时的想象。而且,如果你想增加维度的数量,你必须对 4 个位置进行更改。目前没有办法用数组干净地做到这一点。

      更新:您似乎可以进一步概括代码,因为您可以创建一个动态排名数组。 Programatically Declare Array of Arbitrary Rank 但是这似乎会导致性能损失,这很可能是不可接受的

      类似问题供参考:How to get a dimension (slice) from a multidimensional array

      【讨论】:

        猜你喜欢
        • 2013-05-30
        • 1970-01-01
        • 1970-01-01
        • 2013-05-03
        • 2020-02-19
        • 2013-07-27
        • 2017-05-19
        • 2018-08-19
        • 1970-01-01
        相关资源
        最近更新 更多