跨度和二维数组

问题描述 投票:0回答:6

是否可以将新的 System.Memory Span 结构与二维数据数组一起使用?

double[,] testMulti = 
    {
        { 1, 2, 3, 4 },
        { 5, 6, 7, 8 },
        { 9, 9.5f, 10, 11 },
        { 12, 13, 14.3f, 15 }
    };

double[] testArray = { 1, 2, 3, 4 };
string testString = "Hellow world";

testMulti.AsSpan(); // Compile error
testArray.AsSpan();
testString.AsSpan();

虽然 testArray 和 testString 有 AsSpan 扩展,但 testMulti 不存在这样的扩展。

Span 的设计仅限于处理一维数据数组吗?
我还没有找到使用 Span 处理 testMulti 数组的明显方法。

c# arrays .net multidimensional-array system.memory
6个回答
11
投票

您可以创建一个具有非托管内存的

Span
。这将允许您不加区别地“切片和切块”。 unsafe { Span<T> something = new Span<T>(pointerToarray, someLength); }

完整演示

unsafe public static void Main(string[] args) { double[,] doubles = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 9.5f, 10, 11 }, { 12, 13, 14.3f, 15 } }; var length = doubles.GetLength(0) * doubles.GetLength(1); fixed (double* p = doubles) { var span = new Span<double>(p, length); var slice = span.Slice(6, 5); foreach (var item in slice) Console.WriteLine(item); } }

输出

7 8 9 9.5 10

其他选项是重新分配到单维数组,承担惩罚并且
不要Pass-Go

    BlockCopy
  • 或直接 p/调用 
  • memcpy
  • 并使用
    unsafe
    和指针
  • Cast<T>
  • 例如
    multiDimensionalArrayData.Cast<byte>().ToArray()
    
    
    
  • 前 2 个对于大型数组来说性能更高。


9
投票
MemoryMarshal.CreateSpan

MemoryMarshal.GetArrayDataReference
public static Span<T> AsSpan<T>(this Array array)
{
    return MemoryMarshal.CreateSpan(ref Unsafe.As<byte, T>(ref MemoryMarshal.GetArrayDataReference(array)), array.Length);
}

点网小提琴 这适用于数组的所有维度。如果您希望泛型类型推断起作用,则需要为每个等级(维度级别)使用单独的函数,例如

AsSpan<T>(this T[,] array)

AsSpan<T>(this T[,,] array)
public static Span<T> AsSpan<T>(this T[,] array) => ((Array)array).AsSpan();

public static Span<T> AsSpan<T>(this T[,,] array) => ((Array)array).AsSpan();

public static Span<T> AsSpan<T>(this T[,,,] array) => ((Array)array).AsSpan();

// etc



4
投票

查看文档

这里

您可以在此处
找到寻址 nuget 包。 该软件包还提供了 Memory2D。
var arr = new int[,] { {1,2,3},{2,2,3},{3,2,3} }; var spn = arr.AsSapn2D(); // Now use it similar to a normal span // The access is of course a bit different since we are using a 2D data structure. Console.WriteLine(spn[0..2,..]);



1
投票

您当然可以将各种结构映射到一维内存上,但 Span 类不会为您做这件事。但你可以轻松地自己写一些东西,例如:

public class Span2D<T> where T : struct { protected readonly Span<T> _span; protected readonly int _width; protected readonly int _height; public Span2D(int height, int width) { T[] array = new T[_height * _width]; _span = array.AsSpan(); } public T this[int row, int column] { get { return _span[row * _height + column]; } set { _span[row * _height + column] = value; } } }

棘手的部分是实现
Slice()

,因为对于二维结构来说语义有点模糊。您可能只能按其中一个维度对这种结构进行切片,因为按另一个维度对它进行切片会导致内存不连续。

    


0
投票

您需要首先使用

将二维数组转换为列表(一维)的快速方法

转换二维数组中所示的技术来获取一个新的单维数组。


0
投票

double[][] testMulti = { new double[] { 1, 2, 3, 4 }, new double[] { 5, 6, 7, 8 }, new double[] { 9, 9.5f, 10, 11 }, new double[] { 12, 13, 14.3f, 15 } }; Span<double[]> span = testMulti.AsSpan(2, 1); Span<double> slice = span[0].AsSpan(1, 2); foreach (double d in slice) Console.WriteLine(d); slice[0] = 10.5f; Console.Write(string.Join(", ", testMulti[2])); Console.ReadLine();

输出

9.5 10 9, 10.5, 10, 11

	
© www.soinside.com 2019 - 2024. All rights reserved.