Span и двумерные массивы - PullRequest
       51

Span и двумерные массивы

0 голосов
/ 11 октября 2018

Можно ли использовать новую структуру 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 работой с одномерными массивами данных?
Я не нашел очевидного способа работы с массивом testMulti с использованием Span.

Ответы [ 4 ]

0 голосов
/ 11 октября 2018

Возможно, удастся добиться большего успеха с использованием зубчатого массива вместо многомерного массива.

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
0 голосов
/ 11 октября 2018

Все промежутки являются одномерными, потому что память одномерна.

Конечно, вы можете отобразить все виды структур на одномерную память, но класс 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 голосов
/ 11 октября 2018

Как @saruman, я не верю, что это возможно.

Сначала вам потребуется получить новый одномерный массив, используя методы, показанные в Быстрый способ преобразования двумерного массива в список (одномерный) или Преобразование двухмерного массива, например.

0 голосов
/ 11 октября 2018

Вы можете создать Span с неуправляемой памятью.Это позволит вам Slice and Dice без разбора.

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 / invoke memcpy напрямую и используйте unsafeи указатели
  • Cast<T> например, multiDimensionalArrayData.Cast<byte>().ToArray()

Первые 2 будут более производительными для больших массивов.

...