Можно ли преобразовать массив C # double [,,] в double [] без копирования - PullRequest
5 голосов
/ 18 сентября 2008

У меня в приложении .NET огромные трехмерные массивы чисел. Мне нужно преобразовать их в одномерный массив, чтобы передать его в библиотеку COM. Есть ли способ конвертировать массив без копирования всех данных?

Я могу выполнить преобразование следующим образом, но затем я использую в два раза больше памяти, что является проблемой в моем приложении:

  double[] result = new double[input.GetLength(0) * input.GetLength(1) * input.GetLength(2)];
  for (i = 0; i < input.GetLength(0); i++) 
    for (j = 0; j < input.GetLength(1); j++) 
      for (k = 0; k < input.GetLength(2); k++) 
        result[i * input.GetLength(1) * input.GetLength(2) + j * input.GetLength(2) + k)] = input[i,j,l];
  return result;

Ответы [ 5 ]

8 голосов
/ 18 сентября 2008

Я не верю, что то, как C # хранит эти данные в памяти, сделает это возможным так же, как простое приведение в C. Почему бы не использовать 1d-массив для начала и, возможно, создать класс для типа, чтобы вы могли обращаться к нему в своей программе, как если бы это был 3d-массив?

6 голосов
/ 18 сентября 2008

К сожалению, массивы C # не гарантированно находятся в непрерывной памяти, как на языках, близких к металлическим, как C. Итак, нет. Нет способа конвертировать double [,,] в double [] без поэлементного копирования.

3 голосов
/ 19 сентября 2008

Рассмотрите возможность абстрагирования доступа к данным с помощью Proxy (аналогично итераторам / умным указателям в C ++). К сожалению, синтаксис не так чист, как в C ++, так как operator () недоступен для перегрузки, а operator [] имеет одно аргумент, но все еще закрывается.

Конечно, этот дополнительный уровень абстракции добавляет сложности и самостоятельной работы, но он позволит вам внести минимальные изменения в существующий код, который использует объекты double [,,], в то же время позволяя использовать один double [] массив как для взаимодействия, так и для ваших вычислений в C #.

class Matrix3
{
    // referece-to-element object
    public struct Matrix3Elem{
        private Matrix3Impl impl;
        private uint dim0, dim1, dim2;
        // other constructors
        Matrix3Elem(Matrix3Impl impl_, uint dim0_, uint dim1_, uint dim2_) {
            impl = impl_; dim0 = dim0_; dim1 = dim1_; dim2 = dim2_;
        }
        public double Value{
            get { return impl.GetAt(dim0,dim1,dim2); }
            set { impl.SetAt(dim0, dim1, dim2, value); }
        }
    }

    // implementation object
    internal class Matrix3Impl
    {
        private double[] data;
        uint dsize0, dsize1, dsize2; // dimension sizes
        // .. Resize() 
        public double GetAt(uint dim0, uint dim1, uint dim2) {
            // .. check bounds
            return data[ (dim2 * dsize1 + dim1) * dsize0 + dim0 ];
        }
        public void SetAt(uint dim0, uint dim1, uint dim2, double value) {
            // .. check bounds
            data[ (dim2 * dsize1 + dim1) * dsize0 + dim0 ] = value;
        }
    }

    private Matrix3Impl impl;

    public Matrix3Elem Elem(uint dim0, uint dim1, uint dim2){
        return new Matrix2Elem(dim0, dim1, dim2);
    }
    // .. Resize
    // .. GetLength0(), GetLength1(), GetLength1()
}

И затем использование этого типа для чтения и записи - 'foo [1,2,3]' теперь записывается как 'foo.Elem (1,2,3) .Value', как для чтения значений, так и для записи. значения в левой части выражений присваивания и значения.

void normalize(Matrix3 m){

    double s = 0;
    for (i = 0; i < input.GetLength0; i++)     
        for (j = 0; j < input.GetLength(1); j++)       
            for (k = 0; k < input.GetLength(2); k++)
    {
        s += m.Elem(i,j,k).Value;
    }
    for (i = 0; i < input.GetLength0; i++)     
        for (j = 0; j < input.GetLength(1); j++)       
            for (k = 0; k < input.GetLength(2); k++)
    {
        m.Elem(i,j,k).Value /= s;
    }
}

Опять же, добавлены затраты на разработку, но обмениваются данными, устраняя накладные расходы на копирование и связанные с этим расходы на разработку. Это компромисс.

1 голос
/ 18 сентября 2008

В качестве обходного пути вы можете создать класс, который будет поддерживать массив в одномерной форме (возможно, даже ближе к голой металлической форме, чтобы вы могли легко передать ее в библиотеку COM?), А затем перегрузить оператор [] этого класса, чтобы сделайте его пригодным для использования в качестве многомерного массива в коде C #.

1 голос
/ 18 сентября 2008

Не зная подробностей вашей библиотеки COM, я бы посмотрел на создание класса фасада в .Net и предоставление его COM, при необходимости. Ваш фасад будет иметь двойной [,,] и индексатор, который будет отображаться с [] на [,,].

Редактировать: Я согласен с замечаниями, высказанными в комментариях, предложение Лоренса лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...