ChatGPT解决这个技术问题 Extra ChatGPT

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

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!

I usually change the name from is_found to is_still_hiding. Love the answers though, I needed to do similar for array of int in a test case. (good question)
Create a new struct that actually uses the default value you want, perhaps?

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

While this works it's not really a good solution because it's very slow; it's about 4 times slower than iterating with a for loop in fact.
yes that's true, when we consider performance the for loop is faster
To see some real benchmark have a look at C# Initialize Array.
Enumerable.ToArray doesn't know the size of the enumerable sequence, so it has to guess as to the array size. That means you'll get array allocations every time ToArray's buffer is exceeded, plus one more allocation at the end for the trim. There's also overhead involved with the enumerable object.
Just a note, that with reference types this will fill the whole array with all the references to the same single object. If this is not what you want and you actually want to generate different objects for each array item, see stackoverflow.com/a/44937053/23715.
Y
Yves M.

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

Prefer ++i instead of i++ if you don't need the copy.
i++ copies i, increments i, and returns the original value. ++i just returns the incremented value. Therefore ++i is faster, which can be significant in large loops like we're talking about here.
@RobertDailey: That is a compiler optimization, and no longer true. I just tested to verify my belief: If the return value of i++ isn't used for anything, then the compiler will compile it as ++i automatically for you. Also, even when I do use the return value, the performance difference is so small I needed to make an extreme case in order to measure it. Even then, it resulted in only a few percent different runtime.
I wrote an extension method like this but I had it return the original array to allow for method chaining such as: int[] arr = new int[16].Populate(-1);
Change void to T[] and then you can do var a = new int[100].Polupate(1)
P
Palec

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

Not bad, but it's still slower than a for loop by about a factor of 4x
patjbs in theory in the future Enumerable.Repeat will perform faster because it will use a parallel implementation.
@PetarPetrov This will never happen due to cache thrashing. I'm fairly certain that due to the nature of the CPU cache, performing work in parallel on a single array will always be slower no matter what because the computer expects synchronous work and loads data appropriately.
intended pessimisation != lack of premature optimization.
P
Palec

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


Excellent! Though be aware that it is a relatively new method. It is available in .NET Core 2.0+ and .NET Standard 2.1, but specifically not in any of the .NET Framework versions. (it will be in .NET 5.0, which blends .NET Framework and .NET Core together).
e.g. Array.Fill(myArray, myDefaultValue);
L
LBushkin

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

And to initialize a float[] array: float[] AlzCalDefault = new float[] {(float) 0.5, 18, 500, 1, 0};
FWIW initialization of an array can be done in any version of C# like: bool[] vals = { false, true, false, !(a || b) && c, SomeBoolMethod() };
"avoid the cost of initializing the array slot to the default value" is a nice thought but neither you nor the compiler have any control over that -- the .NET allocator hands out blocks of already-zeroed memory.
M
MrFox

If your array is so large you should use BitArray. It uses 1 bit for every bool instead of a byte (like in an array of bools) also you can set the all the bits to true with bit operators. Or just initialize on true. If you only need to do it once, it will only cost more though.

System.Collections.BitArray falses = new System.Collections.BitArray(100000, false);
System.Collections.BitArray trues = new System.Collections.BitArray(100000, true);

// Now both contain only true values.
falses.And(trues);

b
bashmohandes

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

I'm liking the extension idea the more I dig into this. Sometimes the upfront and simple solution is really the best!
y
yfeldblum

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!


that's similar to what you're trying to do, except its making a function call for each element in your array. It may look much nicer syntactically, but its doing a lot more work...
yeah, it's looking like a simply for loop does the job just about as well as anything else
It creates a new array (doesn't change the original instance).
P
Panos Theof

The code below combines simple iteration for small copies and Array.Copy for large copies

    public static void Populate<T>( T[] array, int startIndex, int count, T value ) {
        if ( array == null ) {
            throw new ArgumentNullException( "array" );
        }
        if ( (uint)startIndex >= array.Length ) {
            throw new ArgumentOutOfRangeException( "startIndex", "" );
        }
        if ( count < 0 || ( (uint)( startIndex + count ) > array.Length ) ) {
            throw new ArgumentOutOfRangeException( "count", "" );
        }
        const int Gap = 16;
        int i = startIndex;

        if ( count <= Gap * 2 ) {
            while ( count > 0 ) {
                array[ i ] = value;
                count--;
                i++;
            }
            return;
        }
        int aval = Gap;
        count -= Gap;

        do {
            array[ i ] = value;
            i++;
            --aval;
        } while ( aval > 0 );

        aval = Gap;
        while ( true ) {
            Array.Copy( array, startIndex, array, i, aval );
            i += aval;
            count -= aval;
            aval *= 2;
            if ( count <= aval ) {
                Array.Copy( array, startIndex, array, i, count );
                break;
            }
        }
    }

The benchmarks for different array length using an int[] array are :

         2 Iterate:     1981 Populate:     2845
         4 Iterate:     2678 Populate:     3915
         8 Iterate:     4026 Populate:     6592
        16 Iterate:     6825 Populate:    10269
        32 Iterate:    16766 Populate:    18786
        64 Iterate:    27120 Populate:    35187
       128 Iterate:    49769 Populate:    53133
       256 Iterate:   100099 Populate:    71709
       512 Iterate:   184722 Populate:   107933
      1024 Iterate:   363727 Populate:   126389
      2048 Iterate:   710963 Populate:   220152
      4096 Iterate:  1419732 Populate:   291860
      8192 Iterate:  2854372 Populate:   685834
     16384 Iterate:  5703108 Populate:  1444185
     32768 Iterate: 11396999 Populate:  3210109

The first columns is the array size, followed by the time of copying using a simple iteration ( @JaredPared implementation ). The time of this method is after that. These are the benchmarks using an array of a struct of four integers

         2 Iterate:     2473 Populate:     4589
         4 Iterate:     3966 Populate:     6081
         8 Iterate:     7326 Populate:     9050
        16 Iterate:    14606 Populate:    16114
        32 Iterate:    29170 Populate:    31473
        64 Iterate:    57117 Populate:    52079
       128 Iterate:   112927 Populate:    75503
       256 Iterate:   226767 Populate:   133276
       512 Iterate:   447424 Populate:   165912
      1024 Iterate:   890158 Populate:   367087
      2048 Iterate:  1786918 Populate:   492909
      4096 Iterate:  3570919 Populate:  1623861
      8192 Iterate:  7136554 Populate:  2857678
     16384 Iterate: 14258354 Populate:  6437759
     32768 Iterate: 28351852 Populate: 12843259

P
Petar Petrov

What about a parallel implementation

public static void InitializeArray<T>(T[] array, T value)
{
    var cores = Environment.ProcessorCount;

    ArraySegment<T>[] segments = new ArraySegment<T>[cores];

    var step = array.Length / cores;
    for (int i = 0; i < cores; i++)
    {
        segments[i] = new ArraySegment<T>(array, i * step, step);
    }
    var remaining = array.Length % cores;
    if (remaining != 0)
    {
        var lastIndex = segments.Length - 1;
        segments[lastIndex] = new ArraySegment<T>(array, lastIndex * step, array.Length - (lastIndex * step));
    }

    var initializers = new Task[cores];
    for (int i = 0; i < cores; i++)
    {
        var index = i;
        var t = new Task(() =>
        {
            var s = segments[index];
            for (int j = 0; j < s.Count; j++)
            {
                array[j + s.Offset] = value;
            }
        });
        initializers[i] = t;
        t.Start();
    }

    Task.WaitAll(initializers);
}

When only initializing an array the power of this code can't be seen but I think you should definitely forget about the "pure" for.


This risks the issue of false sharing, in which different threads compete for CPU cache lines and therefore reducing performance compared to a single-threaded implementation. Whether that happens depends on the size of the per-thread memory blocks and the CPU architecture.
l
l33t

Or... you could simply use inverted logic. Let false mean true and vice versa.

Code sample

// bool[] isVisible = Enumerable.Repeat(true, 1000000).ToArray();
bool[] isHidden = new bool[1000000]; // Crazy-fast initialization!

// if (isVisible.All(v => v))
if (isHidden.All(v => !v))
{
    // Do stuff!
}

funny solution, all though this would be a lot harder with for instance ints because you lose the 0.
this is actually a viable option if you "invert the logic" on the variable name: instead of bool[] isVisible make it bool[] isHidden
People seem to react like this is some kind of funny hack. It's a common optimization technique. If you're lucky, the compiler will do this for you.
E
Eric J.

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

Incrementing blk by BLOCK_SIZE instead of multiplying might be worthwhile. Of course, the right answer is for .Net Core to optimize Array.Fill<T>.
A
Apollo3zehn

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


P
Peter Duniho

.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.


J
Joe Huang

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

Your benchmark is flawed. You wont easily achieve trustworthy results from such a small, isolated environment where the difference comes down to fractions of a nanosecond. Array.Fill is objectively more performant because Fill only needs to access the class member's address once. (And, as is the case with library functions, Fill stands to benefit from any future optimizations.)
S
Stan R.

this also works...but might be unnecessary

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

J
James

There is no way to set all elements in an array as a single operation, UNLESS, that value is the element types default value.

Eg, if it is an array of integers you can set them all to zero with a single operation, like so: Array.Clear(...)


D
DarthGizka

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...


FWIW, C memset isn't applicable for patterns wider than one byte. And C# will give you the fast SIMD copy if you use Buffer.BlockCopy instead of Array.Copy... however it will throw an exception for any aggregate type, BlockCopy is only permitted for primitive types. If using BlockCopy also be careful that the offset and length arguments are not in the same units as Array.Copy.
D
Douglas

If you're planning to only set a few of the values in the array, but want to get the (custom) default value most of the time, you could try something like this:

public class SparseArray<T>
{
    private Dictionary<int, T> values = new Dictionary<int, T>();

    private T defaultValue;

    public SparseArray(T defaultValue)
    {
        this.defaultValue = defaultValue;
    }

    public T this [int index]
    {
      set { values[index] = value; }
      get { return values.ContainsKey(index) ? values[index] ? defaultValue; }
    }
}

You'll probably need to implement other interfaces to make it useful, such as those on array itself.


P
Peter - Reinstate Monica

I realize I'm late to the party but here's an idea. Write a wrapper which has conversion operators to and from the wrapped value so that it can be used as a stand-in for the wrapped type. This was actually inspired by the silly-sounding answer from @l33t.

First (coming from C++) I realized that in C# a default ctor is not called when the elements of an array are constructed. Instead -- even in the presence of a user-defined default constructor! -- all array elements are zero-initialized. That did surprise me.

So a wrapper class which simply provides a default ctor with the desired value would work for arrays in C++ but not in C#. A workaround is to let the wrapper type map 0 to the desired seed value upon conversion. That way zero initialized values appear to be initialized with the seed for all practical purposes:

public struct MyBool
{
    private bool _invertedValue;

    public MyBool(bool b) 
    {   
        _invertedValue = !b;
    }

    public static implicit operator MyBool(bool b)
    {
        return new MyBool(b);
    }

    public static implicit operator bool(MyBool mb)
    {
        return !mb._invertedValue;
    }

}

static void Main(string[] args)
{
        MyBool mb = false; // should expose false.
        Console.Out.WriteLine("false init gives false: " 
                              + !mb);

        MyBool[] fakeBoolArray = new MyBool[100];

        Console.Out.WriteLine("Default array elems are true: " 
                              + fakeBoolArray.All(b => b) );

        fakeBoolArray[21] = false;
        Console.Out.WriteLine("Assigning false worked: " 
                              + !fakeBoolArray[21]);

        fakeBoolArray[21] = true;
        // Should define ToString() on a MyBool,
        // hence the !! to force bool
        Console.Out.WriteLine("Assigning true again worked: " 
                              + !!fakeBoolArray[21]);
}

This pattern is applicable to all value types. One could for example map 0 to 4 for ints if initialization with 4 was desired etc.

I'd love to make a template of it as would be possible in C++, providing the seed value as template parameter, but I understand that's not possible in C#. Or am I missing something? (Of course in C++ mapping is not necessary at all because one can provide a default ctor which will be called for array elements.)

FWIW, here's a C++ equivalent: https://ideone.com/wG8yEh .


s
superstewie

If you can invert your logic you can use the Array.Clear() method to set the boolean array to false.

        int upperLimit = 21;
        double optimizeMe = Math.Sqrt(upperLimit);

        bool[] seiveContainer = new bool[upperLimit];
        Array.Clear(seiveContainer, 0, upperLimit);

C
Cine

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.


what namespace? Does this work for struct arrays or only primitives?
C
Community

There are some more answers on this (duplicate?) question: What is the equivalent of memset in C#?

Someone has benchmarked the alternatives (they included an unsafe version, but they didn't try memset): http://techmikael.blogspot.co.uk/2009/12/filling-array-with-default-value.html


f
fubo

Here is another appraoch with System.Collections.BitArray which has such a constructor.

bool[] result = new BitArray(1000000, true).Cast<bool>().ToArray();

or

bool[] result = new bool[1000000];
new BitArray(1000000, true).CopyTo(result, 0);

P
Peter J

Make a private class inside where you make the array and the have a getter and setter for it. Unless you need each position in the array to be something unique, like random, then use int? as an array and then on get if the position is equal null fill that position and return the new random value.

IsVisibleHandler
{

  private bool[] b = new bool[10000];

  public bool GetIsVisible(int x)
  {
  return !b[x]
  }

  public void SetIsVisibleTrueAt(int x)
  {
  b[x] = false //!true
  }
}

Or use

public void SetIsVisibleAt(int x, bool isTrue)
{
b[x] = !isTrue;
}

As setter.


d
demongolem
Boolean[] data = new Boolean[25];

new Action<Boolean[]>((p) => { BitArray seed = new BitArray(p.Length, true); seed.CopyTo(p, 0); }).Invoke(data);

Please use better formatting and maybe a few explaining words so others can understand your solution better.
You can use this to increase performance of the initialization by partitioning the target array and copying seed to the various partitions. This was only meant to give an idea - This is my first and was my last ever post.