如何用一个值填充/实例化C#数组?

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


我通常将变量名从is_found更改为is_still_hiding。非常感谢提供的答案,我在测试用例中需要对int数组进行类似处理。(好问题) - ctrl-alt-delor
创建一个新的结构体,以实际使用您想要的默认值,也许? - arkon
26个回答

2
我知道我来晚了,但这里有一个想法。编写一个包装器,其中包含转换运算符以及从包装类型到包装值的转换,使其可以用作包装类型的替代品。这实际上是受@l33t愚蠢回答的启发。
首先(来自C ++),我意识到在C#中,当构造数组元素时不会调用默认构造函数。相反,即使存在用户定义的默认构造函数,所有数组元素也将被零初始化。这让我感到惊讶。
因此,一个简单地提供所需值的默认构造函数的包装类将适用于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进行初始化,则可以将0映射到4。

我想制作一个C++的模板,将种子值作为模板参数提供,但我了解在C#中这不可能。或者我错过了什么?(当然,在C++中根本不需要进行映射,因为可以提供默认构造函数,这将调用数组元素。)

顺便说一句,以下是C++的等效代码:https://ideone.com/wG8yEh


2

如果您可以反转逻辑,您可以使用Array.Clear()方法将布尔数组设置为false。

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

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

1

0

这里有另一种方法,使用具有此构造函数的System.Collections.BitArray

bool[] result = new BitArray(1000000, true).Cast<bool>().ToArray();

或者

bool[] result = new bool[1000000];
new BitArray(1000000, true).CopyTo(result, 0);

0

在内部创建一个私有类,其中包含数组及其getter和setter。除非您需要数组中的每个位置都是唯一的,例如随机数,否则请使用int?作为数组类型,并在获取值时,如果该位置为空,则填充该位置并返回新的随机值。

IsVisibleHandler
{

  private bool[] b = new bool[10000];

  public bool GetIsVisible(int x)
  {
  return !b[x]
  }

  public void SetIsVisibleTrueAt(int x)
  {
  b[x] = false //!true
  }
}

或者使用

public void SetIsVisibleAt(int x, bool isTrue)
{
b[x] = !isTrue;
}

作为setter。


-2
Boolean[] data = new Boolean[25];

new Action<Boolean[]>((p) => { BitArray seed = new BitArray(p.Length, true); seed.CopyTo(p, 0); }).Invoke(data);

请使用更好的格式和一些解释性的词语,以便其他人更好地理解您的解决方案。 - Gorgsenegger
1
你可以使用这种方法通过将目标数组分区并将种子复制到各个分区来提高初始化的性能。这只是为了提供一个想法 - 这是我的第一篇,也是我最后一篇帖子。 - ldsmithperrin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接