Самый быстрый способ заполнить массив одним значением

Я хотел бы заполнить 2D-массив одним значением, которое у меня есть, однако, я хотел бы сделать это самым быстрым способом, если длина 2D-массива будет равна 200k +, и со временем будет более 200 из этих массивов. Я просмотрел Buffer.BlockCopy и Array.Copy, однако они оба берут массивы в качестве источника/адресата, где единственный массив, который у меня есть, - это место назначения, причем источником является одиночное значение.

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

Ответ 1

Самый быстрый метод, который я нашел, использует 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);
        }
    }
}

Я написал об этом в https://secureapplicationlifestyle.com/2011/11/initialize-array-to-value-in-c-very.html и https://secureapplicationlifestyle.com/2014/04/better-array-fill-function.html

Ответ 2

Для некоторой связанной информации см. Что такое символ memset в С#?.

Как упоминалось в этом вопросе (довольно близко к обману этого), цикл for обычно лучше всего, если вы не хотите попасть в неуправляемый код.

Итак, это должно быть довольно быстро:

int[] arr = new int[MAX_ELEMENTS];
for (int i = 0; i < arr.Length; ++i)
{
    array[i] = MY_VALUE;
}

Как и все связанные с производительностью, получить что-то работающее, а затем измерить, что такое узкое место. Акцент на "меру". Попытка угадать, что такое узкое место, - это, как правило, плохая идея (:

Ответ 3

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

(Мне бы хотелось увидеть сравнение производительности между этим и наивным циклом для разных типов и размеров массива)