Method to Quickly Initialize All Elements of an Array to a Value

Update 1: I decided to revisit this with a a new blog post

Update 2: A reader (+Michael Hsu) posted an improved version on GitHub and I blogged about it here

In the course of my other work this week, I discovered a method for quickly initializing an array to a single value or to a repeating value.

The theory is based on the idea that Array.Copy is very fast. Understanding that, I copy the value into the array at position zero. Now I keep copying that value into the array, doubling the size of my copy each time.

For example, if my array contained ten elements and my value contains one element (a ‘7’), the operations will look like this.

If you were to iterate through and set each value to ‘7’ directly, you would have to perform ten operations. Here we only performed five operations. The time taken is fairly similar at this level but this method is much faster for large arrays.

To test this I wrote two functions. ArrayFillIterative, which sets each element to a value directly and ArrayFill, which uses Array.Copy to quickly fill all elements. Both do the same thing in that they fill the output array with the input array over and over.

The (fast) Array.Copy Way

public static void ArrayFill<T>(T[] arrayToFill, T fillValue)
{
    // if called with a single value, wrap the value in an array and call the main function
    ArrayFill<T>(arrayToFill, new T[] { fillValue });
}

public static void ArrayFill<T>(T[] arrayToFill, T[] fillValue)
{
    if (fillValue.Length >= arrayToFill.Length)
    {
        throw new ArgumentException("fillValue array length must be smaller than length of arrayToFill");
    }

    // set the initial array value
    Array.Copy(fillValue, arrayToFill, fillValue.Length);

    int arrayToFillHalfLength = arrayToFill.Length / 2;

    for (int i = fillValue.Length; i < arrayToFill.Length; i *= 2)
    {
        int copyLength = i;
        if (i > arrayToFillHalfLength)
        {
            copyLength = arrayToFill.Length - i;
        }

        Array.Copy(arrayToFill, 0, arrayToFill, i, copyLength);
    }
}

The (slow) Iterative Way

public static void ArrayFillIterative<T>(T[] arrayToFill, T[] fillValue)
        {
            int counter = 0;
            int arrayLengthUsed = arrayToFill.Length - fillValue.Length;

            for (int i = 0; i < arrayLengthUsed; i += fillValue.Length)
            {
                for (int x = 0; x <; fillValue.Length; x++)
                {
                    counter = i + x;
                    arrayToFill[counter] = fillValue[x];
                }
            }

            // fill remaining elements</span>
            for (int i = counter + 1, x = 0; i < arrayToFill.Length; i++, x++)
            {
                arrayToFill[i] = fillValue[x];
            }
        }

The Test Results

I worked with a byte array that I sized to hold 357,913,941 elements. The number is fairly random. I needed a large number that would not cause an out of memory exception when the array is instantiated.

I ran the following code to compare the results of filling the array each way.

Stopwatch watch = new Stopwatch();
byte[] myArray1 = new byte[myArrayLength];
byte[] myArray2 = new byte[myArrayLength];

watch.Restart();
ArrayFillIterative(myArray1, fillValue);
watch.Stop();

Debug.Print("Took {0} ticks or {1} milliseconds to iteratively fill an array of type {2} sized at {3}", 
    watch.ElapsedTicks, watch.ElapsedMilliseconds,"byte", myArray1.Length);

watch.Restart();
ArrayFill(myArray2, fillValue);
watch.Stop();

Debug.Print("Took {0} ticks or {1} milliseconds to fill ArrayFill an array of type {2} sized at {3}", 
    watch.ElapsedTicks, watch.ElapsedMilliseconds, "byte", myArray2.Length);

On my machine, the iterative fill took about 2800 milliseconds to fill the byte array with a repeating 4 byte pattern.

In contrast, the array copy method took around 280 milliseconds. That is a one-tenth the time of the original function! It should also be very memory efficient since it uses itself as the source for the copy operation.

Home
Improve Your Life
Improve Your Team
Improve Your Code
Opinion
Software Projects
Foo Network