Чрезвычайно быстрый способ клонирования значений зубчатого массива во второй массив?

В настоящее время я работаю над приложением, которое отвечает за вычисление случайных перестановок зубчатого массива.

В настоящее время основная часть времени в приложении потрачена на копирование массива на каждой итерации (всего 1 миллион итераций). В моей текущей системе весь процесс занимает 50 секунд, и 39 из этих секунд потратили клонирование массива.

Моя процедура клонирования массива такова:

public static int[][] CopyArray(this int[][] source)
 {
 int[][] destination = new int[source.Length][];
 // For each Row
 for (int y = 0; y < source.Length; y++)
 {
 // Initialize Array
 destination[y] = new int[source[y].Length];
 // For each Column
 for (int x = 0; x < destination[y].Length; x++)
 {
 destination[y][x] = source[y][x];
 }
 }
 return destination;
 }

Есть ли способ, безопасный или небезопасный, для достижения того же эффекта, что и выше, намного быстрее?

5 ответов

Любой из них должен работать на вас. Они оба работают примерно столько же времени и намного быстрее, чем ваш метод.

// 100 passes on a int[1000][1000] set size
// 701% faster than original (14.26%)
static int[][] CopyArrayLinq(int[][] source)
{
 return source.Select(s => s.ToArray()).ToArray();
}
// 752% faster than original (13.38%)
static int[][] CopyArrayBuiltIn(int[][] source)
{
 var len = source.Length;
 var dest = new int[len][];
 for (var x = 0; x < len; x++)
 {
 var inner = source[x];
 var ilen = inner.Length;
 var newer = new int[ilen];
 Array.Copy(inner, newer, ilen);
 dest[x] = newer;
 }
 return dest;
}


Вы можете использовать Array.Clone для внутреннего цикла:

public static int[][] CopyArray(this int[][] source)
{
 int[][] destination = new int[source.Length][];
 // For each Row
 for(int y = 0;y < source.Length;y++)
 {
 destination[y] = (int[])source[y].Clone();
 }
 return destination;
}

Другой альтернативой для внутреннего цикла является Buffer.BlockCopy, но я не оценил его производительность против Array.Clone - возможно, это быстрее:

destination[y] = new int[source[y].Length];
Buffer.BlockCopy(source[y], 0, destination[y], 0, source[y].Length * 4);

Изменить: Buffer.BlockCopy принимает число для байтов для копирования параметра count, а не числа элементов массива.


Более быстрый способ копирования объектов - не копировать их вообще - считали ли вы эту опцию? Если вам просто нужно создавать перестановки, вам не нужно копировать данные на каждом из них - просто измените массив. Этот подход не будет работать, если вам нужно продолжать результаты предыдущих вызовов. В любом случае просмотрите свой код, чтобы узнать, не копируете ли вы данные больше времени, которое вам нужно.


Вы просмотрели метод С# Array.Clone?

Изменить: На самом деле, я верю Array.Copy может быть более эффективным/быстрее для ваших нужд.

Я сделал быстрый тест, и похоже, что все изменения в месте назначения не влияют на источник:

int[] source = new int[3]{1,2,3};
int[] destination = new int[source.Length];
Array.Copy(source, destination, source.Length);
destination[0]++; // or destination[0] = destination[0] + 1;

приводит к:

source = { 1 , 2 , 3 }
 destination = { 2, 2, 3 }

Это результат, который вы искали?

public static int[][] CopyArray(int[][] source)
 {
 int[][] destination = new int[source.Length][];
 Array.Copy(source, destination, source.Length);
 return destination;
 }

в основном выполнит то, что вы ищете, я верю.


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

licensed under cc by-sa 3.0 with attribution.