Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Expose a column from a 2D array without copying

I have a 2D array, and I’d like to expose the values within a single column as a 1D array. The code should not involve copying as this is a data processing system that will involve hundreds of Mb of data. The reason for wanting to expose a single column of data is really just to avoid calling code from having access to the entire 2D array.

I found the Span2D<T> type (CommunityToolkit.HighPerformance NuGet package):

var rawData = new double[,];
...
Span2D<double> span = rawData;

The only potentially useful member I found was GetColumn():

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

var column = span.GetColumn(1);

However this returns an enumerator, so the only way I can see of exposing the data as an array is to use .ToArray(). Is it possible to do what I’m trying to achieve, either with Span2D<> or some other approach?

>Solution :

If you can change the consuming code to use an IReadOnlyList<T>, it’s not too much work to write a wrapper class that will expose a column of a matrix (2D array) as an IReadOnlyList<T> vector.

This does add the proverbial "extra level of indirection", but it does also mean that the elements are returned without the need for any array allocations.

It’s essentially working the same way as List<T> does – by wrapping an array – so it might be plenty fast enough for your needs.

Here’s a sample implementation, with error handling elided for brevity:

(Also you can try this online)

public sealed class ArrayColumn<T>: IReadOnlyList<T>
{
    public ArrayColumn(T[,] matrix, int column)
    {
        _matrix = matrix;
        _column = column;
        Count   = _matrix.GetLength(0);
    }

    public IEnumerator<T> GetEnumerator()
    {
        IEnumerable<T> items()
        {
            for (int row = 0; row < Count; ++row)
            {
                yield return _matrix[row, _column];
            }
        }

        return items().GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public int Count { get; }

    public T this[int index] => _matrix[index, _column];

    readonly T[,] _matrix;
    readonly int  _column;
}

With that implementation you can take a vertical slice from a matrix (2D array) and present it as a vector (1D array):

public static void Main()
{
    var matrix = new string[5, 10];

    for (int row = 0; row < matrix.GetLength(0); ++row)
    {
        for (int col = 0; col < matrix.GetLength(1); ++col)
        {
            matrix[row, col] = $"{row}, {col}";
        }
    }

    var col3 = new ArrayColumn<string>(matrix, column: 3); // Grab column 3

    for (int col = 0; col < col3.Count;  ++col)
    {
        Console.WriteLine(col3[col]);
    }

    Console.WriteLine("-----------------");

    foreach (var element in col3)
    {
        Console.WriteLine(element);
    }
}

Output:

0, 3
1, 3
2, 3
3, 3
4, 3
-----------------
0, 3
1, 3
2, 3
3, 3
4, 3
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading