How to populate/instantiate a C# array with a single value?

Viewed 333651

I know that instantiated arrays of value types in C# are automatically populated with the default value of the type (e.g. false for bool, 0 for int, etc.).

Is there a way to auto-populate an array with a seed value that's not the default? Either on creation or a built-in method afterwards (like Java's Arrays.fill())? Say I wanted an boolean array that was true by default, instead of false. Is there a built-in way to do this, or do you just have to iterate through the array with a for loop?

 // Example pseudo-code:
 bool[] abValues = new[1000000];
 Array.Populate(abValues, true);

 // Currently how I'm handling this:
 bool[] abValues = new[1000000];
 for (int i = 0; i < 1000000; i++)
 {
     abValues[i] = true;
 }

Having to iterate through the array and "reset" each value to true seems ineffecient. Is there anyway around this? Maybe by flipping all values?

After typing this question out and thinking about it, I'm guessing that the default values are simply a result of how C# handles the memory allocation of these objects behind the scenes, so I imagine it's probably not possible to do this. But I'd still like to know for sure!

26 Answers
Enumerable.Repeat(true, 1000000).ToArray();

Don't know of a framework method but you could write a quick helper to do it for you.

public static void Populate<T>(this T[] arr, T value ) {
  for ( int i = 0; i < arr.Length;i++ ) {
    arr[i] = value;
  }
}

Create a new array with a thousand true values:

var items = Enumerable.Repeat<bool>(true, 1000).ToArray();  // Or ToList(), etc.

Similarly, you can generate integer sequences:

var items = Enumerable.Range(0, 1000).ToArray();  // 0..999

You can use Array.Fill in .NET Core 2.0+ and .NET Standard 2.1+.

For large arrays or arrays that will be variable sized you should probably use:

Enumerable.Repeat(true, 1000000).ToArray();

For small array you can use the collection initialization syntax in C# 3:

bool[] vals = new bool[]{ false, false, false, false, false, false, false };

The benefit of the collection initialization syntax, is that you don't have to use the same value in each slot and you can use expressions or functions to initialize a slot. Also, I think you avoid the cost of initializing the array slot to the default value. So, for example:

bool[] vals = new bool[]{ false, true, false, !(a ||b) && c, SomeBoolMethod() };

unfortunately I don't think there is a direct way, however I think you can write an extension method for the array class to do this

class Program
{
    static void Main(string[] args)
    {
        int[] arr = new int[1000];
        arr.Init(10);
        Array.ForEach(arr, Console.WriteLine);
    }
}

public static class ArrayExtensions
{
    public static void Init<T>(this T[] array, T defaultVaue)
    {
        if (array == null)
            return;
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = defaultVaue;
        }
    }
}

Well after a little more googling and reading I found this:

bool[] bPrimes = new bool[1000000];
bPrimes = Array.ConvertAll<bool, bool>(bPrimes, b=> b=true);

Which is certainly closer to what I'm looking for. But I'm not sure if that's better than iterating through the original array in a for-loop and just changing the values. After a quick test in fact, it appears slower by about a factor of 5. So not really a good solution then!

.NET Core 2.0 and later supports Array.Fill() method.

Here is a sample code.

var arr = new int[10];
int defaultValue = 2;
Array.Fill(arr,defaultValue);

It also has an overload method for range of indices to be filled. More details can be found here.

If you are on .NET Core, .NET Standard >= 2.1, or depend on the System.Memory package, you can also use the Span<T>.Fill() method:

var valueToFill = 165;
var data = new int[100];

data.AsSpan().Fill(valueToFill);

// print array content
for (int i = 0; i < data.Length; i++)
{
    Console.WriteLine(data[i]);
}

https://dotnetfiddle.net/UsJ9bu

Many of the answers presented here boil down to a loop that initializes the array one element at a time, which does not take advantage of CPU instructions designed to operate on a block of memory at once.

.Net Standard 2.1 (in preview as of this writing) provides Array.Fill(), which lends itself to a high-performance implementation in the runtime library (though as of now, .NET Core doesn't seem to leverage that possibility).

For those on earlier platforms, the following extension method outperforms a trivial loop by a substantial margin when the array size is significant. I created it when my solution for an online code challenge was around 20% over the allocated time budget. It reduced the runtime by around 70%. In this case, the array fill was performed inside another loop. BLOCK_SIZE was set by gut feeling rather than experiment. Some optimizations are possible (e.g. copying all bytes already set to the desired value rather than a fixed-size block).

internal const int BLOCK_SIZE = 256;
public static void Fill<T>(this T[] array, T value)
{
    if (array.Length < 2 * BLOCK_SIZE)
    {
        for (int i = 0; i < array.Length; i++) array[i] = value;
    }
    else
    {
        int fullBlocks = array.Length / BLOCK_SIZE;
        // Initialize first block
        for (int j = 0; j < BLOCK_SIZE; j++) array[j] = value;
        // Copy successive full blocks
        for (int blk = 1; blk < fullBlocks; blk++)
        {
            Array.Copy(array, 0, array, blk * BLOCK_SIZE, BLOCK_SIZE);
        }

        for (int rem = fullBlocks * BLOCK_SIZE; rem < array.Length; rem++)
        {
            array[rem] = value;
        }
    }
}

Just a benchmark:

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.18363.997 (1909/November2018Update/19H2)
Intel Core i7-6700HQ CPU 2.60GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.302
  [Host]        : .NET Core 3.1.6 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.31603), X64 RyuJIT
  .NET Core 3.1 : .NET Core 3.1.6 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.31603), X64 RyuJIT

Job=.NET Core 3.1  Runtime=.NET Core 3.1

|           Method |     Mean |     Error |    StdDev |
|----------------- |---------:|----------:|----------:|
| EnumerableRepeat | 2.311 us | 0.0228 us | 0.0213 us |
|  NewArrayForEach | 2.007 us | 0.0392 us | 0.0348 us |
|        ArrayFill | 2.426 us | 0.0103 us | 0.0092 us |
    [SimpleJob(BenchmarkDotNet.Jobs.RuntimeMoniker.NetCoreApp31)]
    public class InitializeArrayBenchmark {
        const int ArrayLength = 1600;

        [Benchmark]
        public double[] EnumerableRepeat() {
            return Enumerable.Repeat(double.PositiveInfinity, ArrayLength).ToArray();
        }

        [Benchmark]
        public double[] NewArrayForEach() {
            var array = new double[ArrayLength];

            for (int i = 0; i < array.Length; i++) {
                array[i] = double.PositiveInfinity;
            }

            return array;
        }

        [Benchmark]
        public double[] ArrayFill() {
            var array = new double[ArrayLength];
            Array.Fill(array, double.PositiveInfinity);

            return array;
        }
    }

this also works...but might be unnecessary

 bool[] abValues = new bool[1000];
 abValues = abValues.Select( n => n = true ).ToArray<bool>();

Here's another version for us Framework users abandoned by Microsoft. It is 4 times as fast as Array.Clear and faster than Panos Theof's solution and Eric J's and Petar Petrov's parallel one - up to two times as fast for large arrays.

First I want to present you the function's ancestor, because that makes it easier to understand the code. Performance-wise this is pretty much on par with Panos Theof's code, and for some things that may already be enough:

public static void Fill<T> (T[] array, int count, T value, int threshold = 32)
{
    if (threshold <= 0)
        throw new ArgumentException("threshold");

    int current_size = 0, keep_looping_up_to = Math.Min(count, threshold);

    while (current_size < keep_looping_up_to)
        array[current_size++] = value;

    for (int at_least_half = (count + 1) >> 1; current_size < at_least_half; current_size <<= 1)
        Array.Copy(array, 0, array, current_size, current_size);

    Array.Copy(array, 0, array, current_size, count - current_size);
}

As you can see, this is based on repeated doubling of the already-initialised part. This is simple and efficient, but it runs afoul of modern memory architectures. Hence was born a version that uses doubling only to create a cache-friendly seed block, which is then blasted iteratively over the target area:

const int ARRAY_COPY_THRESHOLD = 32;  // 16 ... 64 work equally well for all tested constellations
const int L1_CACHE_SIZE = 1 << 15;

public static void Fill<T> (T[] array, int count, T value, int element_size)
{
    int current_size = 0, keep_looping_up_to = Math.Min(count, ARRAY_COPY_THRESHOLD);

    while (current_size < keep_looping_up_to)
        array[current_size++] = value;

    int block_size = L1_CACHE_SIZE / element_size / 2;
    int keep_doubling_up_to = Math.Min(block_size, count >> 1);

    for ( ; current_size < keep_doubling_up_to; current_size <<= 1)
        Array.Copy(array, 0, array, current_size, current_size);

    for (int enough = count - block_size; current_size < enough; current_size += block_size)
        Array.Copy(array, 0, array, current_size, block_size);

    Array.Copy(array, 0, array, current_size, count - current_size);
}

Note: the earlier code needed (count + 1) >> 1 as limit for the doubling loop to ensure that the final copy operation has enough fodder to cover all that is left. This would not be the case for odd counts if count >> 1 were to be used instead. For the current version this is of no significance since the linear copy loop will pick up any slack.

The size of an array cell must be passed as a parameter because - the mind boggles - generics aren't allowed to use sizeof unless they use a constraint (unmanaged) that may or may not become available in the future. Wrong estimates are not a big deal but performance is best if the value is accurate, for the following reasons:

  • Underestimating the element size can lead to block sizes greater than half the L1 cache, hence increasing the likelihood of copy source data getting evicted from L1 and having to be re-fetched from slower cache levels.

  • Overestimating the element size results in under-utilisation of the CPU's L1 cache, meaning the linear block copy loop gets executed more often than it would be with optimal utilisation. Thus, more of the fixed loop/call overhead is incurred than strictly necessary.

Here's a benchmark pitting my code against Array.Clear and the other three solutions mentioned previously. The timings are for filling integer arrays (Int32[]) of the given sizes. In order to reduce variation caused by cache vagaries etc. each test was executed twice, back to back, and the timings were taken for the second execution.

array size   Array.Clear      Eric J.   Panos Theof  Petar Petrov   Darth Gizka
-------------------------------------------------------------------------------
     1000:       0,7 µs        0,2 µs        0,2 µs        6,8 µs       0,2 µs 
    10000:       8,0 µs        1,4 µs        1,2 µs        7,8 µs       0,9 µs 
   100000:      72,4 µs       12,4 µs        8,2 µs       33,6 µs       7,5 µs 
  1000000:     652,9 µs      135,8 µs      101,6 µs      197,7 µs      71,6 µs 
 10000000:    7182,6 µs     4174,9 µs     5193,3 µs     3691,5 µs    1658,1 µs 
100000000:   67142,3 µs    44853,3 µs    51372,5 µs    35195,5 µs   16585,1 µs 

Should the performance of this code not be sufficient then a promising avenue would be parallelising the linear copy loop (with all threads using the same source block), or our good old friend P/Invoke.

Note: clearing and filling of blocks is normally done by runtime routines that branch to highly specialised code using MMX/SSE instructions and whatnot, so in any decent environment one would simply call the respective moral equivalent of std::memset and be assured of professional performance levels. IOW, by rights the library function Array.Clear should leave all our hand-rolled versions in the dust. The fact that it is the other way around shows how far out of whack things really are. Same goes for having to roll one's own Fill<> in the first place, because it is still only in Core and Standard but not in the Framework. .NET has been around for almost twenty years now and we still have to P/Invoke left and right for the most basic stuff or roll our own...

I am a bit surprised noone has made the very simple, yet ultra fast, SIMD version:

  public static void PopulateSimd<T>(T[] array, T value) where T : struct
  {
     var vector = new Vector<T>(value);
     var i = 0;
     var s = Vector<T>.Count;
     var l = array.Length & ~(s-1);
     for (; i < l; i += s) vector.CopyTo(array, i);
     for (; i < array.Length; i++) array[i] = value;
  }

Benchmark: (Number are for Framework 4.8, but Core3.1 is statistically the same)

|     Method |       N |           Mean |          Error |        StdDev | Ratio | RatioSD |
|----------- |-------- |---------------:|---------------:|--------------:|------:|--------:|
| DarthGizka |      10 |      25.975 ns |      1.2430 ns |     0.1924 ns |  1.00 |    0.00 |
|       Simd |      10 |       3.438 ns |      0.4427 ns |     0.0685 ns |  0.13 |    0.00 |
|            |         |                |                |               |       |         |
| DarthGizka |     100 |      81.155 ns |      3.8287 ns |     0.2099 ns |  1.00 |    0.00 |
|       Simd |     100 |      12.178 ns |      0.4547 ns |     0.0704 ns |  0.15 |    0.00 |
|            |         |                |                |               |       |         |
| DarthGizka |    1000 |     201.138 ns |      8.9769 ns |     1.3892 ns |  1.00 |    0.00 |
|       Simd |    1000 |     100.397 ns |      4.0965 ns |     0.6339 ns |  0.50 |    0.00 |
|            |         |                |                |               |       |         |
| DarthGizka |   10000 |   1,292.660 ns |     38.4965 ns |     5.9574 ns |  1.00 |    0.00 |
|       Simd |   10000 |   1,272.819 ns |     68.5148 ns |    10.6027 ns |  0.98 |    0.01 |
|            |         |                |                |               |       |         |
| DarthGizka |  100000 |  16,156.106 ns |    366.1133 ns |    56.6564 ns |  1.00 |    0.00 |
|       Simd |  100000 |  17,627.879 ns |  1,589.7423 ns |   246.0144 ns |  1.09 |    0.02 |
|            |         |                |                |               |       |         |
| DarthGizka | 1000000 | 176,625.870 ns | 32,235.9957 ns | 1,766.9637 ns |  1.00 |    0.00 |
|       Simd | 1000000 | 186,812.920 ns | 18,069.1517 ns | 2,796.2212 ns |  1.07 |    0.01 |

As can be seen, it is much faster at <10000 elements, and only slightly slower beyond that.

Related