Dynamically Building Arrays in .NET

Ok so this is one of my favorite tips in .NET. Of course, there are a lot of things I like about the framework, but anyhow…

A lot of times you’ll want to create an array of items, but you don’t know how big the array is going to be. You’re hoping you can declare an array & just dynamically add items to it like you can with an ArrayList. The first impulse might be to do something like

string[] foo = new string[] { };
foo[1] = “some text”;
foo[2] = “some text”;

But, that won’t work — you’ll get an System.IndexOutOfBoundsException.

However, in .NET 1.1, your friend the ArrayList comes to the rescue with this fun stuff:

ArrayList fooArrayList = new ArrayList();
fooArrayList.Add(“some text”);
fooArrayList.Add(“some more text”);

string[] foo = (string[])fooArrayList.ToArray(typeof(string));

Yay! Now you can dynamically add stuff to an array. But wait, there’s more — with .NET 2.0, the Array class somes with a new Resize() generic method, so you can also do this:

string[] foo3 = new string[]{};

// resize array & add an item
Array.Resize<string>(ref foo3, foo3.Length + 1);
foo3[foo3.Length 1] = “some text”;

// resize array & add an item
Array.Resize<string>(ref foo3, foo3.Length + 1);
foo3[foo3.Length 1] = “some text”;

So that’s cool. But which is faster, you ask? Let’s see, here’s the code we used to add 10,000 items to an array.

const int MAX_ITEMS = 100000;
DateTime start;
TimeSpan timeTaken;

// time ArrayList
start = DateTime.Now;
ArrayList fooArrayList = new ArrayList();
for (int i = 0; i < MAX_ITEMS; i++)
{
fooArrayList.Add(“some text”);
}
string[] foo2 = (string[])fooArrayList.ToArray(typeof(string));
timeTaken = DateTime.Now.Subtract(start);
Console.WriteLine(“ArrayListt” + timeTaken.Milliseconds + ” msecnn”);

// time Array.Resize
start = DateTime.Now;
string[] foo3 = new string[] { };
for (int i = 0; i < MAX_ITEMS; i++)
{
Array.Resize<string>(ref foo3, foo3.Length + 1);
foo3[foo3.Length 1] = “some text”;
}
timeTaken = DateTime.Now.Subtract(start);
Console.WriteLine(“Resizet” + timeTaken.Milliseconds + ” msecnn”);

// prompt for ENTER
Console.WriteLine(“Press ENTER.”);
Console.ReadLine();

Final result: ArrayList 0 msec, Array.Resize 250 msec. If we go for 100,000 items, it ends up being ArrayList 10 msec, Array.Resize 45000 msec. ;(

So, that’s not surprising. The ArrayList probably only resizes things when it needs to and keeps a buffer. So what if we change Array.Resize to resize the Array in chunks of, say, 10,000? And let’s go for 1,000,000 items in the array.

const int MAX_ITEMS = 1000000;
DateTime start;
TimeSpan timeTaken;

// time ArrayList
start = DateTime.Now;
ArrayList fooArrayList = new ArrayList();
for (int i = 0; i < MAX_ITEMS; i++)
{
fooArrayList.Add(“some text”);
}
string[] foo2 = (string[])fooArrayList.ToArray(typeof(string));
timeTaken = DateTime.Now.Subtract(start);
Console.WriteLine(“ArrayListt” + timeTaken.Milliseconds + ” msecnn”);

// time Array.Resize
start = DateTime.Now;
string[] foo3 = new string[] { };
int itemCount = 0;
int arrayChunkSize = 10000;
for (int i = 0; i < MAX_ITEMS; i++)
{
// only resize the array if we need to, and do it in chunks
if (foo3.Length <= itemCount)
Array.Resize<string>(ref foo3, itemCount + arrayChunkSize);
foo3[itemCount] = “some text”;
itemCount++;
}
// trim the final size of the array
Array.Resize<string>(ref foo3, itemCount);
timeTaken = DateTime.Now.Subtract(start);
Console.WriteLine(“Resizet” + timeTaken.Milliseconds + ” msecnn”);

// prompt for ENTER
Console.WriteLine(“Press ENTER.”);
Console.ReadLine();

Much better. ArrayList 150 msec, Array.Resize (chunked) 700 msec. But, ArrayList is still faster. So I guess ArrayList is pretty efficient about expanding its buffer when you add items to it, which is a good thing, since I like ArrayLists.

So…there’s your tip, plus we looked at a new Array generic method, and did a bit of performance analysis. If you need a dynamically-sized array, just use an ArrayList and cast it to an array using the .ToArray function. Remember, you can do this for any array, even an array of custom objects.

0