Span and two dimensional Arrays

删除回忆录丶 提交于 2019-12-13 14:24:04

问题


Is it possible to use the new System.Memory Span struct with two dimensional arrays of data?

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();

Whilst testArray and testString have a AsSpan extension, no such extension exists for testMulti.

Is the design of Span limited to working with single dimensional arrays of data?
I've not found an obvious way of working with the testMulti array using Span.


回答1:


You can create a Span with unmanaged memory. This will allow you to Slice and Dice indiscriminately.

unsafe
{
    Span<T> something = new Span<T>(pointerToarray, someLength); 
}

Full Demo

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

Output

7
8
9
9.5
10

Other options would be to reallocate to a single dimension array, cop the penalty and do not Pass-Go

  • BlockCopy
  • or p/invoke memcpy directly and use unsafe and pointers
  • Cast<T> eg multiDimensionalArrayData.Cast<byte>().ToArray()

The first 2 will be more performant for large arrays.




回答2:


All spans are one-dimensional because memory is one-dimensional.

You can of course map all manner of structures onto one-dimensional memory, but the Span class won't do it for you. But you could easily write something yourself, for example:

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

The tricky part is implementing Slice(), since the semantics are sort of ambiguous for a two-dimensional structure. You can probably only slice this sort of structure by one of the dimensions, since slicing it by the other dimension would result in memory that is not contiguous.




回答3:


As @saruman I don't believe it's possible.

You will need to get a new single dimension array first using techniques shown in Fast way to convert a two dimensional array to a List ( one dimensional ) or Convert 2 dimensional array, for example.




回答4:


Perhaps there's more success to be had working with a jagged array instead of a multidimensional array.

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();

OUTPUT

9.5
10
9, 10.5, 10, 11


来源:https://stackoverflow.com/questions/52750582/span-and-two-dimensional-arrays

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!