views:

1741

answers:

14

I've always been told that adding an element to an array happens like this:

An empty copy of the array+1element is created and then the data from the original array is copied into it then the new data for the new element is then loaded

If this is true, then using an array within a scenario that requires a lot of element activity is contra-indicated due to memory and cup utilization, correct?

If that is the case, shouldn't you try to avoid using an array as much as possible when you will be adding a lot of elements? Should you use iStringMap instead? If so, what happens if you need more than 2 dimensions AND need to add a lot of element additions do you just take the performance hit or is there something else that should be used?


PS:If your answering the question, consider moding the question up to give your answers more of a chance of being seen by the public.

+2  A: 

When the array is resized, a new array must be allocated, and the contents copied. If you are only modifying the contents of the array, it is just a memory assignment.

So, you should not use arrays when you don't know the size of the array, or the size is likely to change. However, if you have a fixed length array, they are an easy way of retrieving elements by index.

Abe Heidebrecht
+7  A: 

Look at the generic List<T> as a replacement for arrays. They support most of the same things arrays do, including allocating an initial storage size if you want.

Joel Coehoorn
If designing re-usable or framework-like components, consider using the base classes or interfaces, ICollection<T> or IEnumerable<T>. Static code analysis should tell you about this and link to better information (it's for inheritance and such).
Anthony Mastrean
+1  A: 

The best thing you can do is allocate as much memory as you need upfront if possible. This will prevent .Net from having to make additional calls to get memory on the heap. Failing that then it makes sense to allocate in chunks of 5 or whatever number makes sense for your application.

This is a rule you can apply to anything really.

Jon
+1  A: 

A standard array should be defined with a length, which reserves all of the memory that it needs in a contiguous block. Adding an item to the array would put it inside of the block of already reserved memory.

+2  A: 

In general, I prefer to avoid array usage. Just use List<T>. It uses a dynamically-sized array internally, and is fast enough for most usage. If you're using multi-dimentional arrays, use List<List<List<T>>> if you have to. It's not that much worse in terms of memory, and is much simpler to add items to.

If you're in the 0.1% of usage that requires extreme speed, make sure it's your list accesses that are really the problem before you try to optimize it.

Jonathan
+2  A: 

ArrayList and List grow the array by more than one when needed (I think it's by doubling the size, but I haven't checked the source). They are generally the best choice when you are building a dynamically sized array.

When your benchmarks indicate that array resize is seriously slowing down your application (remember - premature optimization is the root of all evil), you can evaluate writing a custom array class with tweaked resizing behavior.

Tom Ritter
+1  A: 

Arrays are great for few writes and many reads, particularly those of an iterative nature - for anything else, use one of the many other data structures.

Greg Hurlman
+4  A: 

If you're going to be adding/removing elements a lot, just use a List. If it's multidimensional, you can always use a List<List<int>> or something.

On the other hand, lists are less efficient than arrays if what you're mostly doing is traversing the list, because arrays are all in one place in your CPU cache, where objects in a list are scattered all over the place.

If you want to use an array for efficient reading but you're going to be "adding" elements frequently, you have two main options:

1) Generate it as a List (or List of Lists) and then use ToArray() to turn it into an efficient array structure.

2) Allocate the array to be larger than you need, then put the objects into the pre-allocated cells. If you end up needing even more elements than you pre-allocated, you can just reallocate the array when it fills, doubling the size each time. This gives O(log n) resizing performance instead of O(n) like it would be with a reallocate-once-per-add array. Note that this is pretty much how StringBuilder works, giving you a faster way to continually append to a string.

apenwarr
In .NET, the list is actually an ArrayList, which uses an Array as the backing store. Calling ToArray simply returns a copy of the array that is storing the values. In other words, the List<T> is a wrapper around a resizable array.
Abe Heidebrecht
A list is not all over the place. If you for some reason are boxing value types, then sure, the elements will be spread out, but a List<T> uses an array internally, so in that respect, it won't be worse off.
Lasse V. Karlsen
I have to vote it down because it's wrong. It may surprise you to learn that all .NET collections are based on arrays. I believe the reason is for locality of reference and reducing GC overhead.
Mike Dimmick
If your array is of objects they will still be scattered all over the place. The array will simply be an array of references. If you want the data to be IN the array you need to use structs.
Rick Minerich
Also, your O(n) resize implies n items in the array. This is what a resize will always cost because each reference must be copied into the new array. One resize per add would be O(n) add, not O(n) resize.
Rick Minerich
This is a wrong answer.
Andrei Rinea
+1  A: 

You are correct an array is great for look ups. However modifications to the size of the array are costly.

You should use a container that supports incremental size adjustments in the scenario where you're modifying the size of the array. You could use an ArrayList which allows you to set the initial size, and you could continually check the size versus the capacity and then increment the capacity by a large chunk to limit the number of resizes.

Or you could just use a linked list. Then however look ups are slow...

Sam
Don't use ArrayList in .Net 2.0 and later. Use the generic List<T> for the type you are storing.
Joel Coehoorn
+4  A: 

This really depends on what you mean by "add."

If you mean:

T[] array;
int i;
T value;
...
if (i >= 0 && i <= array.Length)
    array[i] = value;

Then, no, this does not create a new array, and is in-fact the fastest way to alter any kind of IList in .NET.

If, however, you're using something like ArrayList, List, Collection, etc. then calling the "Add" method may create a new array -- but they are smart about it, they don't just resize by 1 element, they grow geometrically, so if you're adding lots of values only every once in a while will it have to allocate a new array. Even then, you can use the "Capacity" property to force it to grow before hand, if you know how many elements you're adding (list.Capacity += numberOfAddedElements)

Alex Lyman
+1  A: 

This forum post might or might not be of some use to you regarding efficiency of various array types: C# arrays - multidimensional vs lexicographic

Grank
+1  A: 

If I think I'm going to be adding items to the collection a lot over its lifetime, than I'll use a List. If I know for sure what the size of the collection will be when its declared, then I'll use an array.

Another time I generally use an array over a List is when I need to return a collection as a property of an object - I don't want callers adding items that collection via List's Add methods, but instead want them to add items to the collection via my object's interface. In that case, I'll take the internal List and call ToArray and return an array.

John Christensen
You might want to reconsider returning an array copy of your internal list from a property: http://stackoverflow.com/questions/35007/how-to-expose-a-collection-property
Emperor XLII
+2  A: 

Generally, if you must have the BEST indexed lookup performance it's best to build a List first and then turn it into a array thus paying a small penalty at first but avoiding any later. If the issue is that you will be continually adding new data and removing old data then you may want to use a ArrayList or List for convenience but keep in mind that they are just special case Arrays. When they "grow" they allocate a completely new array and copy everything into it which is extremely slow.

ArrayList is just an Array which grows when needed. Add is amortized O(1), just be careful to make sure the resize won't happen at a bad time. Insert is O(n) all items to the right must be moved over. Remove is O(n) all items to the right must be moved over.

Also important to keep in mind that List is not a linked list. It's just a typed ArrayList. The List documentation does note that it performs better in most cases but does not say why.

The best thing to do is to pick a data structure which is appropriate to your problem. This depends one a LOT of things and so you may want to browse the System.Collections.Generic Namespace.

In this particular case I would say that if you can come up with a good key value Dictionary would be your best bet. It has insert and remove that approaches O(1). However, even with a Dictionary you have to be careful not to let it resize it's internal array (an O(n) operation). It's best to give them a lot of room by specifying a larger-then-you-expect-to-use initial capacity in the constructor.

-Rick

Rick Minerich
+1  A: 

If you are going to be doing a lot of adding, and you will not be doing random access (such as myArray[i]). You could consider using a linked list (LinkedList<T>), because it will never have to "grow" like the List<T> implementation. Keep in mind, though, that you can only really access items in a LinkedList<T> implementation using the IEnumerable<T> interface.

Michael Meadows