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

321,466

Solution 1

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

Solution 2

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

Solution 3

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

Solution 4

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

Solution 5

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() };
Share:
321,466

Related videos on Youtube

patjbs
Author by

patjbs

Lifer

Updated on July 11, 2021

Comments

  • patjbs
    patjbs almost 3 years

    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!

    • ctrl-alt-delor
      ctrl-alt-delor over 12 years
      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)
  • Nader Shirazie
    Nader Shirazie almost 15 years
    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...
  • patjbs
    patjbs almost 15 years
    That's a pretty good idea Jared - I'm definitely thinking I may be adding something like this to my extension library if no other answers pop up!
  • patjbs
    patjbs almost 15 years
    yeah, it's looking like a simply for loop does the job just about as well as anything else
  • patjbs
    patjbs almost 15 years
    Not bad, but it's still slower than a for loop by about a factor of 4x
  • patjbs
    patjbs almost 15 years
    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.
  • patjbs
    patjbs almost 15 years
    I'm liking the extension idea the more I dig into this. Sometimes the upfront and simple solution is really the best!
  • Rony
    Rony almost 15 years
    yes that's true, when we consider performance the for loop is faster
  • helloV
    helloV almost 14 years
    patjbs in theory in the future Enumerable.Repeat will perform faster because it will use a parallel implementation.
  • void.pointer
    void.pointer over 12 years
    Prefer ++i instead of i++ if you don't need the copy.
  • theknut
    theknut about 12 years
    To see some real benchmark have a look at C# Initialize Array.
  • MrFox
    MrFox almost 12 years
    funny solution, all though this would be a lot harder with for instance ints because you lose the 0.
  • Andrew Mao
    Andrew Mao over 11 years
    Robert Dailey - could you explain?
  • Steve B
    Steve B over 11 years
    @RobertDailey: yes robert, please explain :)
  • Jim Lahman
    Jim Lahman over 11 years
    And to initialize a float[] array: float[] AlzCalDefault = new float[] {(float) 0.5, 18, 500, 1, 0};
  • tenpn
    tenpn over 11 years
    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.
  • Jeppe Stig Nielsen
    Jeppe Stig Nielsen about 11 years
    It creates a new array (doesn't change the original instance).
  • Edward Ned Harvey
    Edward Ned Harvey about 11 years
    @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.
  • Gorgsenegger
    Gorgsenegger almost 10 years
    Please use better formatting and maybe a few explaining words so others can understand your solution better.
  • ldsmithperrin
    ldsmithperrin almost 10 years
    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.
  • Gutblender
    Gutblender over 9 years
    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);
  • heijp06
    heijp06 about 9 years
    FWIW initialization of an array can be done in any version of C# like: bool[] vals = { false, true, false, !(a || b) && c, SomeBoolMethod() };
  • Mary Ellen Bench
    Mary Ellen Bench almost 9 years
    I would optimize it, though I don't know for sure compiler doesn't do it automatically, to int arrLength = arr.Length; And use that inside instead of constantly having to call .Length every iteration.
  • Edward Brey
    Edward Brey about 8 years
    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.
  • Markus Hütter
    Markus Hütter about 8 years
    this is actually a viable option if you "invert the logic" on the variable name: instead of bool[] isVisible make it bool[] isHidden
  • l33t
    l33t over 7 years
    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.
  • Broots Waymb
    Broots Waymb over 7 years
    Nice, simple solution for filling small arrays (< 10 elements) when I'm feeling lazy and don't care about the small performance hit.
  • Simon MᶜKenzie
    Simon MᶜKenzie about 7 years
    @MaryEllenBench, blogs.msdn.microsoft.com/ericgu/2004/04/18/…: "The JIT looks for [this pattern], and knows how to optimize it"
  • TernaryTopiary
    TernaryTopiary about 7 years
    @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.
  • orad
    orad almost 7 years
    Change void to T[] and then you can do var a = new int[100].Polupate(1)
  • osjerick
    osjerick over 6 years
    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.
  • Élie
    Élie over 5 years
    @Gutblender Would you want to allow chaining in a case like this due to the side effects? I don't think it makes sense outside of a Builder.
  • alexpanter
    alexpanter over 5 years
    Should we not declare arr.Length as a variable before running the loop? Otherwise we are making a function call for each iteration of the loop to (re)read the array length. It actually has a significant performance overhead for large arrays, and the compiler cannot actually be trusted to make this optimization automatically.
  • Thomas Levesque
    Thomas Levesque almost 5 years
    @EdwardBrey that's no longer true in .NET Core. Many optimizations has been made to Linq to Objects. Repeat now propagates the actual number of elements and ToArray uses it to allocate an array of the correct size directly.
  • Edward Brey
    Edward Brey almost 5 years
    @ThomasLevesque I'm looking at RepeatIterator and don't see how the consumer of IEnumerator is going to know that repeat is done until it has called MoveNext a million times.
  • Thomas Levesque
    Thomas Levesque almost 5 years
    @EdwardBrey sorry, my bad. They made this optimization for other scenarios (e.g. Select), so I would have expected it to be done for Repeat as well. RepeatIterator would have to implement IIListProvider<TSource>, but it doesn't.
  • Thomas Levesque
    Thomas Levesque almost 5 years
    Actually, it does: source.dot.net/#System.Linq/System/Linq/… (IPartition<TSource> inherits from IIListProvider<TSource>), so it should work as I said.
  • Eric J.
    Eric J. almost 5 years
    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.
  • Eric J.
    Eric J. almost 5 years
    @JaredPar .NET Standard 2.1 provides Array.Fill, though the current implementation in .NET Core 3 Preview 7 internally performs the same loop you do. I imagine they intend to provide an implementation that leverages more efficient CPU instructions at some point. I provided an extension method in my answer far, far down the page that significantly outperforms a simple loop for large arrays.
  • Denis Gladkiy
    Denis Gladkiy almost 5 years
    intended pessimisation != lack of premature optimization.
  • Denis Gladkiy
    Denis Gladkiy almost 5 years
    intended pessimisation != lack of premature optimization.
  • Aisah Hamzah
    Aisah Hamzah almost 4 years
    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).
  • NetMage
    NetMage over 3 years
    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>.
  • Marcos Pereira
    Marcos Pereira about 3 years
    @patjbs if you're doing it less than a thousand times per second it probably doesn't matter.
  • Ben Voigt
    Ben Voigt over 2 years
    what namespace? Does this work for struct arrays or only primitives?
  • Ben Voigt
    Ben Voigt over 2 years
    @ワイきんぐ: Caching the result of arr.Length is actually much much worse, because the comparison to arr.Length is what allows the JIT to skip bounds-checks when accessing arr[i].
  • Ben Voigt
    Ben Voigt over 2 years
    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.
  • Ben Voigt
    Ben Voigt over 2 years
    "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.
  • Cine
    Cine over 2 years
  • Chris Halcrow
    Chris Halcrow over 2 years
    e.g. Array.Fill(myArray, myDefaultValue);
  • arkon
    arkon almost 2 years
    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.)