33

What is the slickest way to initialize an array of dynamic size in C# that you know of?

This is the best I could come up with

private bool[] GetPageNumbersToLink(IPagedResult result)
{
   if (result.TotalPages <= 9)
      return new bool[result.TotalPages + 1].Select(b => true).ToArray();

   ...
Ardalan Shahgholi
  • 11,967
  • 21
  • 108
  • 144
Rob
  • 1,983
  • 2
  • 20
  • 29

7 Answers7

74

If by 'slickest' you mean fastest, I'm afraid that Enumerable.Repeat may be 20x slower than a for loop. See http://dotnetperls.com/initialize-array:

Initialize with for loop:             85 ms  [much faster]
Initialize with Enumerable.Repeat:  1645 ms 

So use Dotnetguy's SetAllValues() method.

Nigel Touch
  • 1,946
  • 2
  • 19
  • 12
38

use Enumerable.Repeat

Enumerable.Repeat(true, result.TotalPages + 1).ToArray()
ebram khalil
  • 8,252
  • 7
  • 42
  • 60
Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
  • 12
    I think Nigel's performance note warrants a mention - http://stackoverflow.com/questions/136836/c-array-initialization-with-non-default-value/1051227#1051227 – CrimsonX May 24 '10 at 22:47
  • 11
    I can't believe people upvote for something that's so 'fuzzy' (in my opinion) and costly for an operation as simple as filling an array. `var arr = new type[10]; for (int i = 0; i < arr.Length; i++) arr[i] = value;`, 76 characters of code that everyone understands :). Compared to 67 characters of fuzziness. – Aidiakapi Feb 09 '12 at 17:00
14

EDIT: as a commenter pointed out, my original implementation didn't work. This version works but is rather un-slick being based around a for loop.

If you're willing to create an extension method, you could try this

public static T[] SetAllValues<T>(this T[] array, T value) where T : struct
{
    for (int i = 0; i < array.Length; i++)
        array[i] = value;

    return array;
}

and then invoke it like this

bool[] tenTrueBoolsInAnArray = new bool[10].SetAllValues(true);

As an alternative, if you're happy with having a class hanging around, you could try something like this

public static class ArrayOf<T>
{
    public static T[] Create(int size, T initialValue)
    {
        T[] array = (T[])Array.CreateInstance(typeof(T), size);
        for (int i = 0; i < array.Length; i++)
            array[i] = initialValue;
        return array;
    }
}

which you can invoke like

bool[] tenTrueBoolsInAnArray = ArrayOf<bool>.Create(10, true);

Not sure which I prefer, although I do lurv extension methods lots and lots in general.

Neil Hewitt
  • 2,518
  • 18
  • 24
  • I don't believe your SetAllValues will work: In your lambda expression, x is not passed by reference, so assigning a value to it doesn't change the value stored in the array. – Samuel Jack May 06 '09 at 11:46
  • Yeah, you're absolutely right. I mentioned I hadn't actually compiled it which would have shown up that rather elementary error. I replaced the ForEach with a simple loop and that works fine, but it's not slick as the questioner demanded. – Neil Hewitt May 06 '09 at 12:53
  • 1
    Other than that, your extension method has a signature that implies that it will return a new array, but it modifies the original array and returns that instead. Bad form. – Robert Jeppesen Oct 07 '09 at 11:34
  • One, call your `SetAllValues` `Fill`, its a better name I feel. Two, take advantage of type inference of C# in your second case. So some declaration like this is possible: `ArrayEx.Create(10, true);`. – nawfal Sep 13 '13 at 05:25
  • You don't need `Array.CreateInstance`, just do `new T[]`. – Ohad Schneider Oct 09 '14 at 11:32
5

I would actually suggest this:

return Enumerable.Range(0, count).Select(x => true).ToArray();

This way you only allocate one array. This is essentially a more concise way to express:

var array = new bool[count];

for(var i = 0; i < count; i++) {
   array[i] = true;
}

return array;
Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
1

Many times you'd want to initialize different cells with different values:

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

Or in the factory flavor:

public static T[] GenerateInitializedArray<T>(int size, Func<int, T> factory)
{
    var arr = new T[size];
    for (int i = 0; i < arr.Length; i++)
    {
        arr[i] = factory(i);
    }
    return arr;
}
Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198
1

As of writing this answer, all answers overlook the functionality provided by .NET explicitly for this that calls, and I quote .NET code comments, their "optimized workhorse method" for all types that are not 1 byte in size. If it is only a byte in size then memset will be intrinsically called.

If you're interested in how it works, the workhorse method involves a combination of vectorization and loop unrolling to set all elements in a guaranteed contiguous region of memory with a span to the given value. The guarantee allows for even further build and JIT optimizations. To vectorize this process, there are four constraints:

  1. The architecture must support SIMD instructions,
  2. The type must not be or contain references,
  3. The size of the type must not be greater than the amount of lanes in a byte vector,
  4. And the size of the type must be a power of two.

To take advantage of this, all you need is a single call to Array.Fill or to a span's Fill method. Here is an example:

var a = new bool[1_000];
Array.Fill(a, true); // Same as: a.AsSpan().Fill(true);
Console.WriteLine(String.Join(", ", a));
pvc pipe
  • 63
  • 7
0

Untested, but could you just do this?

return result.Select(p => true).ToArray();

Skipping the "new bool[]" part?

Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
Matt Hamilton
  • 200,371
  • 61
  • 386
  • 320