-1

Based on these two posts (here and here), I understand that it may be possible to write my own extension method for grabbing a 2D slice from a 3D array. I'm working with 3D arrays that represent spatial data in the following way: [layer, row, col]. I'd like to slice over the layer index such that I get a 2D array of all row, col values for the selected layer. However, I haven't been able to work out a way to return a 2D array from the extension method. Here is what I've tried so far, but it errors as noted by the comment // Error: ...:

double[,,] hds    // 3D array of values
double[,] lay_hd; // 2D slice to be filled by extension method

for(int k = 0; k < nlay; k++)
{
    lay_hd = gwhds.SliceLayer(k);  // Error: Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<double>' to 'double[*,*]'
    // write 2D array to text file...
}

public static IEnumerable<T> SliceLayer<T>(this T[,,] array, int lay)
{
    for (var i = array.GetLowerBound(1); i <= array.GetUpperBound(1); i++)
    {
        for (var j = array.GetLowerBound(2); j <= array.GetUpperBound(2); j++)
        {
            yield return array[lay, i, j];
        }
    }
}

Is it possible to return a 2D array from an extension method?

user2256085
  • 483
  • 4
  • 15
  • It's not at all clear what you actually are looking for here. Please fix your question so that there's no ambiguity. Your `SliceLayer()` method returns an enumerable, but the variable you are trying to assign it to is a `double[,]`. There's no way that can work. There are plenty of posts already on the site explaining how to return a `double[,]` in this scenario; if that's all you want, your question is a duplicate. If you think it's not, please explain why it's not. – Peter Duniho Mar 05 '21 at 00:56

1 Answers1

1

Those two posts show that you can get a one dimensional IEnumerable<T> slice out of a 2D array, but for a slice of a 3D array, you would get a 2D IEnumerable<IEnumerable<T>> slice.

public static IEnumerable<IEnumerable<T>> SliceLayer<T>(this T[,,] array, int lay)
{
    IEnumerable<T> SliceRow(int row) {
        for (var j = array.GetLowerBound(2); j <= array.GetUpperBound(2); j++)
        {
            yield return array[lay, row, j];
        }
    }

    for (var i = array.GetLowerBound(1); i <= array.GetUpperBound(1); i++)
    {
        yield return SliceRow(i);
    }
}

However, it seems like the caller expects a 2D array (double[,]), rather than an IEnumerable. In that case you can't use iterator blocks.

public static T[,] SliceLayer<T>(this T[,,] array, int lay)
{
    T[,] result = new T[array.GetLength(1), array.GetLength(2)];
    var lowerBound1 = array.GetLowerBound(1);
    var lowerBound2 = array.GetLowerBound(2);
    for (var i = lowerBound1; i <= array.GetUpperBound(1); i++)
    {
        for (var j = lowerBound2; j <= array.GetUpperBound(2); j++)
        {
            // you could just use i and j as indices here if the input 
            // arrays is guaranteed to have non-negative lower bounds
            result[i - lowerBound1, j - lowerBound2] = array[lay, i, j];
        }
    }
    return result;
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313