How to get cross section of a 3-dimensional C # array

Let's say you have a 3 dimensional array in C #

int space[width, height, depth];

      

And you want to implement the method

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

      

Where "position" is the point along the "dimension" specified where you want to extract your slice. It is important not to use the fact that we are only dealing with 3 dimensions, in the examples below you can correct them by adding if statements and assuming that the matrix will not grow beyond 3 dimensions.

My first attempt (commented problem areas):

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

      

And my second try, just as unhelpful:

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

      

Both of these attachments face dead ends. How would you decide? It is enough to have fixed iteration loops for the number of space dimensions [,]. If the number of dimensions grows, then this is somewhat manageable. Smart / limited if statutes can work, but not excessive if for every dimension.

+3


source to share


3 answers


A few weeks later, when I did other things, and after I met Mika, I answered a little:

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

      

Conclusion: Arrays are not a data structure to do this unless you have this kind of dynamic behavior.



The above code was somewhat on the lines that I was imagining when I wrote the question. However, if you want to increase the number of measurements, you have to change 4 locations. There is currently no way to do this with arrays.

Refresh . It looks like you can generalize the code further, since you can create a dynamic rank array. Programmatically declare an array of arbitrary rank However, this seems to come with a performance penalty, which is most likely unacceptable

Similar question for reference: How to get size (slice) from multidimensional array

+1


source


Quick draft:

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

      



It can be generalized to any number of dimensions (and even make the code smaller and simpler).

+2


source


Didn't debug it but suggested that it should work

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

      

+1


source







All Articles