Самый быстрый способ заполнить массив одним значением
Я хотел бы заполнить 2D-массив единственным значением, которое у меня есть, однако я бы хотел сделать это как можно быстрее, если длина 2D-массива составит в общей сложности 200k+, и со временем будет более 200 из этих массивов., Я рассмотрел Buffer.BlockCopy и Array.Copy, однако, они оба принимают массивы в качестве источника / назначения, где единственный массив, который у меня есть, - это пункт назначения, причем источником является одно значение.
Какой самый быстрый способ заполнить массив с источником, представляющим собой одно значение, а не массив?
3 ответа
Самый быстрый метод, который я нашел, использует Array.Copy, причем размер копии удваивается каждый раз в цикле. Скорость в основном одинакова, заполняете ли вы массив одним значением или массивом значений.
В моем тесте с 20 000 000 элементов массива эта функция в два раза быстрее цикла for.
using System;
namespace Extensions
{
public static class ArrayExtensions
{
public static void Fill<T>(this T[] destinationArray, params T[] value)
{
if (destinationArray == null)
{
throw new ArgumentNullException("destinationArray");
}
if (value.Length >= destinationArray.Length)
{
throw new ArgumentException("Length of value array must be less than length of destination");
}
// set the initial array value
Array.Copy(value, destinationArray, value.Length);
int arrayToFillHalfLength = destinationArray.Length / 2;
int copyLength;
for(copyLength = value.Length; copyLength < arrayToFillHalfLength; copyLength <<= 1)
{
Array.Copy(destinationArray, 0, destinationArray, copyLength, copyLength);
}
Array.Copy(destinationArray, 0, destinationArray, copyLength, destinationArray.Length - copyLength);
}
}
}
Я писал об этом в блогах по адресу http://coding.grax.com/2011/11/initialize-array-to-value-in-c-very.html и http://coding.grax.com/2014/04/better-array-fill-function.html
Для некоторой связанной информации посмотрите Что эквивалентно memset в C#?,
Как упоминалось в этом вопросе (довольно близко к этому вопросу), цикл for обычно лучше, если вы не хотите входить в неуправляемый код.
Так что это должно быть довольно быстро:
int[] arr = new int[MAX_ELEMENTS];
for (int i = 0; i < arr.Length; ++i)
{
array[i] = MY_VALUE;
}
Как и во всех вещах, связанных с производительностью, получите что-то работающее, а затем измерьте, что является узким местом. Акцент на "меру". Попытка угадать, что является узким местом, обычно является плохой идеей (:
Array.Copy
скорее всего лучше оптимизировать, чем цикл for, так что используйте его.
void FillArray<T>(T[] arr, T fillValue)
{
int i = 0;
if (arr.Length > 16) {
{
do {
array[i++] = fillValue;
} while (i < arr.Length)
while (i + 16 < arr.Length) {
Array.Copy(arr, 0, arr, i, 16);
i = i + 16;
}
}
while (i < arr.Length)
{
array[i++] = fillValue;
}
}
(Хотелось бы увидеть сравнение производительности между этим и наивным циклом for для разных типов и размеров массивов)