我知道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#在幕后处理这些对象的内存分配的结果,所以我想这可能是不可能的。但我还是想确定一下!
我有点惊讶没有人做了非常简单,但超快的SIMD版本:
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;
}
基准测试:(数据来自于Framework 4.8,但Core3.1在统计上是相同的)
| 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 |
可以看到,在小于10000个元素时速度要快得多,超过10000个元素时速度仅略慢。
如果你计划只设置数组中的几个值,但大多数时候想要获得(自定义)默认值,你可以尝试这样做:
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; }
}
}
您可能需要实现其他接口以使其有用,例如在数组本身上的接口。