我知道c#中实例化的值类型数组会自动填充该类型的默认值(例如bool为false, int为0,等等)。
是否有一种方法来自动填充一个不是默认的种子值的数组?无论是在创建或之后的内置方法(如Java的Arrays.fill())?假设我想要一个默认为true的布尔数组,而不是false。是否有一个内置的方法来做到这一点,或者你只需要通过一个for循环迭代数组?
// 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;
}
必须遍历数组并将每个值“重置”为true似乎效率不高。还有其他方法吗?也许通过翻转所有值?
在输入这个问题并思考之后,我猜默认值只是c#在幕后处理这些对象的内存分配的结果,所以我想这可能是不可能的。但我还是想确定一下!
这里给出的许多答案都可以归结为一个循环,每次初始化数组中的一个元素,它没有利用设计为一次操作内存块的CPU指令。
. net Standard 2.1(在撰写本文时的预览版中)提供了Array.Fill(),这有助于在运行时库中实现高性能(尽管到目前为止,. net Core似乎还没有利用这种可能性)。
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;
}
}
}
只是一个基准:
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;
}
}