简体   繁体   English

公开二维数组中的列而不复制

[英]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.代码不应涉及复制,因为这是一个涉及数百 Mb 数据的数据处理系统。 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):我找到了Span2D<T>类型(CommunityToolkit.HighPerformance NuGet 包):

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

The only potentially useful member I found was GetColumn():我发现的唯一可能有用的成员是 GetColumn():

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() .但是,这会返回一个枚举器,因此我可以看到将数据公开为数组的唯一方法是使用.ToArray() Is it possible to do what I'm trying to achieve, either with Span2D<> or some other approach?是否可以使用 Span2D<> 或其他方法来实现我想要实现的目标?

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.如果您可以更改使用代码以使用IReadOnlyList<T> ,那么编写一个包装器 class 将矩阵(二维数组)的列公开为IReadOnlyList<T>向量的工作量并不大。

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.它本质上与List<T>的工作方式相同 - 通过包装一个数组 - 所以它可能足够快以满足您的需求。

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: Output:

0, 3
1, 3
2, 3
3, 3
4, 3
-----------------
0, 3
1, 3
2, 3
3, 3
4, 3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM