How to populate/instantiate a C# array with a single value?
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() };
Related videos on Youtube
Comments
-
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 over 12 yearsI 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 almost 15 yearsthat'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 almost 15 yearsThat'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 almost 15 yearsyeah, it's looking like a simply for loop does the job just about as well as anything else
-
patjbs almost 15 yearsNot bad, but it's still slower than a for loop by about a factor of 4x
-
patjbs almost 15 yearsWhile 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 almost 15 yearsI'm liking the extension idea the more I dig into this. Sometimes the upfront and simple solution is really the best!
-
Rony almost 15 yearsyes that's true, when we consider performance the for loop is faster
-
helloV almost 14 yearspatjbs in theory in the future Enumerable.Repeat will perform faster because it will use a parallel implementation.
-
void.pointer over 12 yearsPrefer ++i instead of i++ if you don't need the copy.
-
theknut about 12 yearsTo see some real benchmark have a look at C# Initialize Array.
-
MrFox almost 12 yearsfunny solution, all though this would be a lot harder with for instance ints because you lose the 0.
-
Andrew Mao over 11 yearsRobert Dailey - could you explain?
-
Steve B over 11 years@RobertDailey: yes robert, please explain :)
-
Jim Lahman over 11 yearsAnd to initialize a float[] array:
float[] AlzCalDefault = new float[] {(float) 0.5, 18, 500, 1, 0};
-
tenpn over 11 yearsi++ 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 about 11 yearsIt creates a new array (doesn't change the original instance).
-
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 almost 10 yearsPlease use better formatting and maybe a few explaining words so others can understand your solution better.
-
ldsmithperrin almost 10 yearsYou 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 over 9 yearsI 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 about 9 yearsFWIW 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 almost 9 yearsI 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 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 timeToArray
'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 about 8 yearsthis is actually a viable option if you "invert the logic" on the variable name: instead of
bool[] isVisible
make itbool[] isHidden
-
l33t over 7 yearsPeople 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 over 7 yearsNice, 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 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 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 almost 7 yearsChange
void
toT[]
and then you can dovar a = new int[100].Polupate(1)
-
osjerick over 6 yearsJust 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 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 over 5 yearsShould 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 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 andToArray
uses it to allocate an array of the correct size directly. -
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 calledMoveNext
a million times. -
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 forRepeat
as well.RepeatIterator
would have to implementIIListProvider<TSource>
, but it doesn't. -
Thomas Levesque almost 5 yearsActually, it does: source.dot.net/#System.Linq/System/Linq/… (
IPartition<TSource>
inherits fromIIListProvider<TSource>
), so it should work as I said. -
Eric J. almost 5 yearsThis 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. 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 almost 5 yearsintended pessimisation != lack of premature optimization.
-
Denis Gladkiy almost 5 yearsintended pessimisation != lack of premature optimization.
-
Aisah Hamzah almost 4 yearsExcellent! 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 over 3 yearsIncrementing
blk
byBLOCK_SIZE
instead of multiplying might be worthwhile. Of course, the right answer is for .Net Core to optimizeArray.Fill<T>
. -
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 over 2 yearswhat namespace? Does this work for
struct
arrays or only primitives? -
Ben Voigt over 2 years@ワイきんぐ: Caching the result of
arr.Length
is actually much much worse, because the comparison toarr.Length
is what allows the JIT to skip bounds-checks when accessingarr[i]
. -
Ben Voigt over 2 yearsFWIW, C
memset
isn't applicable for patterns wider than one byte. And C# will give you the fast SIMD copy if you useBuffer.BlockCopy
instead ofArray.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 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 over 2 years
-
Chris Halcrow over 2 yearse.g.
Array.Fill(myArray, myDefaultValue);
-
arkon almost 2 yearsYour 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 becauseFill
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.)