我知道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#在幕后处理这些对象的内存分配的结果,所以我想这可能是不可能的。但我还是想确定一下!


当前回答

如果你可以反转你的逻辑,你可以使用array . clear()方法将布尔数组设置为false。

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

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

其他回答

没有办法将数组中的所有元素设置为单个操作,除非,该值是元素类型的默认值。

例如,如果它是一个整数数组,你可以通过一个操作将它们全部设置为0,如下所示: Array.Clear(…)

我知道我来晚了,但我有个主意。编写一个包装器,其中包含与被包装值之间的转换操作符,以便它可以用作被包装类型的替身。这实际上是受到@l33t的愚蠢回答的启发。

首先(来自c++),我意识到在c#中,当数组的元素被构造时,默认的ctor是不被调用的。相反,即使存在用户定义的默认构造函数!——所有数组元素都是零初始化的。这确实让我大吃一惊。

因此,包装器类只提供一个默认的ctor和所需的值,就可以用于c++中的数组,但不适用于c#。一种解决方法是让包装器类型在转换时将0映射到所需的种子值。这样一来,在所有实际应用中,零初始化值似乎都被种子初始化了:

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

此模式适用于所有值类型。例如,如果需要初始化4,则可以将int类型的0映射到4。

我很想像在c++中那样做一个模板,提供种子值作为模板参数,但我知道这在c#中是不可能的。还是我遗漏了什么?(当然,在c++中,映射根本不是必需的,因为可以提供一个默认的ctor,它将被数组元素调用。)

FWIW,这里有一个等价的c++: https://ideone.com/wG8yEh。

只是一个基准:

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;
        }
    }
Enumerable.Repeat(true, 1000000).ToArray();

我不知道框架方法,但你可以写一个快速助手来帮你做。

public static void Populate<T>(this T[] arr, T value ) {
  for ( int i = 0; i < arr.Length;i++ ) {
    arr[i] = value;
  }
}