30

It seems like List<T> in C# can do everything an array can do and more, and seems also just as efficient in memory and performance as an array.

So why would I ever want to use an array?

I'm obviously not asking about cases where an API or other external constraint (i.e. the Main function) requires me to use an array... I'm only asking about creating new data structures in my own code.

We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is right, ideally with citations. Answers that don't include explanations may be removed.

closed as off-topic by gnat, user53019, user40980, Doc Brown, gbjbaanb Dec 11 '14 at 8:41

  • This question does not appear to be about software engineering within the scope defined in the help center.
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 56
    To implement List<T> – ratchet freak Dec 10 '14 at 15:31
  • 43
    is also just as efficient in memory and performance as an array - um. Where did you get that notion from? – Oded Dec 10 '14 at 15:33
  • 12
    Multiple dimensions like var test = new string[5,5] ;) – Knerd Dec 10 '14 at 15:33
  • 7
    There's also the commonly used byte[] array. – SBoss Dec 10 '14 at 16:40
  • 11
    For C# specifically, Eric Lippert wrote about this in blogs.msdn.com/b/ericlippert/archive/2008/09/22/…. – Mephy Dec 10 '14 at 16:45

14 Answers 14

26

The same reason I don't drive a truck when going to work. I don't use something that I won't use the features of.

First of all an array is a primitive construct so an array is faster and more efficient than a List<> for sure, so your argument is not true. Array is also available everywhere and known by developers using different languages and platforms.

The most important reason I use an array instead of a List<> is to imply that the data is fixed length. If I won't add or remove any items from that data collection, I want to make sure that the type reflects that.

Another thing is let's say you are implementing a new data structure and you've read some papers about it. Now while implementing specific algorithms, you can't always rely on someone else's implementation of a type that is general purpose. It changes from .NET to Mono and even between different versions of the framework.

And it is sometimes easier to port a piece of code that uses an array instead of a framework dependent type.

  • 4
    How is an array "faster" than a list, considering that List<T> is implemented using an array? If you know the element count beforehand (which you have to know, when using an array), you can use that knowledge when initializing the list as well. – Theodoros Chatzigiannakis Dec 10 '14 at 21:28
  • 1
    @TheodorosChatzigiannakis When using an array we allocate the memory and simply make assignments, plain malloc(), no overhead. When you are using List<> you will "Add" items and when adding items List<> makes some boundary checking and calls EnsureCapacity method which will copy the contents to another newly allocated array if the current capacity is not enough. It means if you don't need to dynamically allocate new memory, List's performance is not as good as array. – Mert Akcakaya Dec 10 '14 at 23:01
  • 4
    What you're saying is correct, but it assumes that either we don't know the element count beforehand (in which case, arrays aren't useful anyway) or that we do know the element count beforehand but we deliberately don't use it in the case of the list. If we do use the element count to initialize the list with the desired capacity, we get only one array allocation (until you reach that capacity), thus we pay the same performance costs. All other common operations are equal (search, retrieval by index, assignment by index), except for further adds (which arrays don't have at all). – Theodoros Chatzigiannakis Dec 10 '14 at 23:59
  • 3
    @TheodorosChatzigiannakis: Arrays are faster than lists. Just run a simple benchmark to check. – Mehrdad Dec 11 '14 at 0:01
  • 1
    @TheodorosChatzigiannakis, Yes, but there are still boundary checks. – Mert Akcakaya Dec 11 '14 at 0:08
18

You need arrays to manage your collection of mutable structs, of course, and what would we do without those.

struct EvilMutableStruct { public double X; } // don't do this

EvilMutableStruct[] myArray = new EvilMutableStruct[1];
myArray[0] = new EvilMutableStruct()
myArray[0].X = 1; // works, this modifies the original struct

List<EvilMutableStruct> myList = new List<EvilMutableStruct>();
myList.Add(new EvilMutableStruct());
myList[0].X = 1; // does not work, the List will return a *copy* of the struct

(note that there may be some cases where an array of mutable struct is desireable, but usually this differing behavior of mutable structs within arrays versus other collections is a source of errors that should be avoided)


More seriously, you need an array if you want to pass an element by reference. i.e.

Interlocked.Increment(ref myArray[i]);  // works
Interlocked.Increment(ref myList[i]);   // does not work, you can't pass a property by reference

That can be useful for lock-free threadsafe code.


You need an array if you quickly and efficiently want to initialize your fixed-size collection with the default value.

double[] myArray = new double[1000]; // contains 1000 '0' values
                                     // without further initialisation

List<double> myList = new List<double>(1000) // internally contains 1000 '0' values, 
                                             // since List uses an array as backing storage, 
                                             // but you cannot access those
for (int i =0; i<1000; i++) myList.Add(0);   // slow and inelegant

(note that it would be possible to implement a constructor for List that does the same, it's just that c# does not offer this feature)


you need an array if you want to efficiently copy parts of the collection

Array.Copy(array1, index1, array2, index2, length) // can't get any faster than this

double[,] array2d = new double[10,100];
double[] arraySerialized = new double[10*100];
Array.Copy(array2d, 0, arraySerialized, 0, arraySerialized.Length);
// even works for different dimensions

(again, this is something that could be implemented for List as well, but this feature does not exist in c#)

  • If a type is supposed to represent a group of related-but-independent variables stuck together with duct tape (e.g. the coordinates of a point), an exposed-field struct is the best representation. If a variable is supposed to hold a bunch of such groups, an array of that structure type is the best representation. One shouldn't use mutable structs in places where one wants an object, but that doesn't mean one should use objects or things that pretend to be objects in places where one wants a bunch of variables stuck together with duct tape. – supercat Dec 10 '14 at 20:42
  • There are some situations where you may want a mutable struct, such as when you need the last bit of performance and cannot afford heap allocations and references, and in that case an array of structs is your best bet. Good essay here. But I would disagree that a class should not represent "a bunch of variables stuck together". Conceptually structs and classes are mostly the same, the differences are primarily because of implementation details. – HugoRune Dec 10 '14 at 21:17
  • If one wishes to use a collection of mutable-object references as a collection of independent groups of independent variables, one must establish and maintain an invariant that each element identifies an object to which no other non-ephemeral references exist anywhere in the universe. That can certainly be done (and often is), but there is nothing in the language or framework to assist the programmer in upholding that invariant. By contrast, a length-100 array of a structure type with four instance fields will automatically and permanently encapsulate 400 independent variables. – supercat Dec 11 '14 at 15:40
  • I think these comments are the wrong place to discuss this issue further, and seeing as you added your own answer, there does not seem to be a need to duplicate this information here. Suffice to say, arrays can be used for managing mutable structs. Whether and when to use the implementation behaviour of those structs to enforce certain data constraints really goes beyond the scope of my answer. – HugoRune Dec 11 '14 at 15:57
15

So why would I ever want to use an array?

Rarely, you will have a scenario where you know that you need a fixed number of elements. From a design perspective, this should be avoided. If you need 3 things, the nature of business means that you'll very often need 4 in the next release.

Still, when this rare scenario actually occurs, using an array to enforce that fixed size invariant is useful. It provides a signal to other programmers that it is a fixed size, and helps prevent misuse where someone adds or removes an element - breaking expectations elsewhere in code.

  • 23
    The size of arrays is not set in stone at the time one writes code. It can, and often is, a run-time variable. It just never changes after the array has been created. – user7043 Dec 10 '14 at 15:55
  • 11
    It's not unusual to deal with a fixed number of elements. If you're working with 3D points, you probably won't be working with 5D points at any point in the future. The bigger issues with arrays is that they're mutable and don't have convenient labels attached to their elements. – Doval Dec 10 '14 at 17:18
  • 3
    @JanDvorak Lists can shrink or grow and thus don't make sense in any context involving a fixed number of elements. – Doval Dec 10 '14 at 17:28
  • 9
    Rarely? Not everyone works on super-complicated ultra-configurable enterprise monstrosities. – whatsisname Dec 10 '14 at 18:03
  • 3
    It is very common to have a fixed number of elements. Just make sure the length is defined by a constant, so when the next release increase the number of elements from 3 to 4, you just change the constant and everything that relies on this is adapted. – Hans Dec 10 '14 at 19:06
9

Your question has actually already been answered before.

and seems also just as efficient in memory and performance as an array.

It isn't. From the question I linked:

List/foreach:  3054ms (589725196)
Array/foreach: 1860ms (589725196)

Arrays are twice as fast in certain important cases. I am certain the memory usage also differs non-trivially.

Since the main premise of your question is thus defeated, I'm assuming this answers your question. In addition to this, sometimes arrays are forced on you by Win32 API, or your GPU's shader, or some other non-DotNet library.

Even within DotNet, some methods consume and/or return arrays (such as String.Split). Which means either you must now eat the cost of calling ToList and ToArray all the time, or you must conform and use array, possibly continuing the cycle by propagating this to poor downstream users of your code.

More questions and answers on Stack Overflow on this topic:

  • Interestingly, that answer points out that if you use old-fashioned indexed loops (for instead of foreach) the performance difference is minimal. – user949300 Dec 11 '14 at 17:09
3

In addition to reasons listed in other answers, array literal takes fewer characters to declare:

var array = new [] { "A", "B", "C" };
var list = new List<string>() { "A", "B", "C" };

Using array instead of List makes the code a bit shorter and just a bit more readable in cases when (1) you need to pass any IEnumerable<T> literal, or (2) where other functionality of List doesn't matter and you need to use some list-like literal.

I've done this occasionally in unit tests.

  • 1
    Yes just to add. It also works of you need to pass an IList <T> – Esben Skov Pedersen Dec 10 '14 at 19:13
  • +1, often I have some operation for a couple of objects of the same type which are not in a collection. It's easy, short and clear to write foreach( var x in new []{ a, b, c ) ) DoStuff( x ) or new []{ a, b, c ).Select( ... ) etc – stijn Dec 10 '14 at 19:38
3

This is strictly from an OO perspective.

While I can't think of a reason to pass just an array around, I can certainly see situations where an array representation internal to the class is probably the best choice.

While there are other options that give similar characteristics, none seem as intuitive as an array for problems dealing with processing permutations, nested for loops, matrix representation, bitmaps and data interleaving algorithms.

There's a substantial number of scientific fields that rely on matrix math extensively. (e.g. image processing, data error correction, digital signal processing, a ream of applied mathematics problems). Most of the algorithms in those fields are written in terms of using multidimensional arrays/matrixes. So it would be more natural to implement the algorithms as they are defined rather than make them more "software" friendly at the expense of losing the direct tie-ins to the papers the algorithms are based upon.

Like I said, in these cases you can probably get away with using lists but that adds yet another layer of complexity on top of what are already complex algorithms.

3

This actually goes for other languages which have lists as well (such as Java or Visual Basic). There are cases where you need to use an array because a method returns an array instead of a List.

In an actual program, I don't think an array will be used very often, but sometimes you know the data will be a fixed size and you like the small performance gain you get from using an array. Micro-optimisation would be a valid reason, just as a method returning a list, or the need for a multidimensional datastructure.

  • 1
    Many languages don't even have separate list and array collections. On the other hand, using list<T> where vector<T> will work is a disastrously bad idea in C/C++. – Gort the Robot Dec 10 '14 at 16:46
  • 1
    "Because a method returns an array" -- this is a misfeature of Java, forcing programmers to crap up the code with "Arrays.asList(x)". T[] should at least implement Iterable<T> – kevin cline Dec 10 '14 at 18:18
  • 4
    @StevenBurnap - it certainly is disastrously bad in C, because there's no way to compile that code. – Pete Becker Dec 10 '14 at 19:04
  • @PeteBecker The expression vector<T> x compiles just fine for me in C. :-) – svick Dec 11 '14 at 2:08
  • Sorry, I meant the C hand-rolled equivalent to list<T>. Basically, I've seen lots of performance problems caused by developers just using lists by default when an array was a better choice. – Gort the Robot Dec 11 '14 at 19:16
1

Well, I found a use for arrays in a game I have been writing. I used it for creating an inventory system with a fixed number of slots. This had several benefits:

  1. I knew exactly how many open inventory slots the game object had by looking and seeing which slots were null.
  2. I knew exactly what index each item was in.
  3. It was still a "typed" array (Item[] Inventory), so I could add/remove the objects of type "Item".

I figured that if I ever needed to "increase" the size of the inventory, I could do so by transferring the old items into the new array, but since the inventory was fixed by screen space and I had no need to dynamically make it larger/smaller, it worked well for the purpose I was using it for.

1

If you're traversing all elements of a list, then no, an array is not necessary, 'next' or arbitrary 'selection without replacement' will do fine.

But if your algorithm needs random access to the elements in the collection, then, yes, an array is necessary.

This is somewhat analogous to "is goto necessary?". In a reasonable modern language it is not needed at all. But if you peel away the abstractions, at some point, that's all that is actually available to you, that is, the only way to implement these abstractions is with the 'unnecessary' feature. (Of course, the analogy isn't perfect, I don't think anyone says that arrays are poor programming practice; they are easy to understand and think about).

  • List<T> also offers random access. Sure, it's implemented with an array, but that doesn't need to bother you, the user. So at best, you offered a single reason to use arrays: To implement List<T>. – user7043 Dec 10 '14 at 19:46
  • @delnan I think that's my point with respect to abstractions. Sometimes it is better to think in terms of an array, not just for efficiency reasons. (of course sometimes it is way better to think of a linked list, and way better than that to think of a list (without caring about links or otherwise how it is implemented), and way better just a collection. – Mitch Dec 10 '14 at 20:05
0

Legacy compatibility.

All form personal experience:

Legacy programmers - my colleague uses arrays everywhere, has done for 30+ years, good luck changing his mind with your new fangled ideas.

Legacy code - foo(array bar[]) sure you can use a list/vector/collection toarray function but if you not using any of there additional features its easier to use an array to begin with, often more readable without the type switching.

Legacy boss - my boss was a good programmer before she went into management many years ago and still thinks she's up to date, "were using arrays" can end a meeting, explaining what a collection is can cost everyone lunch.

  • 3
    colleagues that are 20 years behind the curve and a boss that wants to know what data types you're using... I love this site for reminding myself how much worse my job could be – JoelFan Dec 10 '14 at 17:24
  • 1
    about 40% of what we do is embedded design where discussions are held in KB, he likes to tell me hes not outdated hes specalised lol – Skeith Dec 10 '14 at 17:28
0

1) There is no multi-dimensional version of List. If your data has more than one dimension it will be very inefficient to use lists.

2) When you are dealing with a large number of small data types (say, a map where all you have is one byte for the terrain type) there can be considerable performance differences due to caching. The array version loads several items per memory read, the list version loads only one. Furthermore, the array version holds several times as many cells in the cache as the list version--if you're repeatedly processing the data this can make a big difference if the array version fits in cache but the list version does not.

For an extreme case, consider Minecraft. (Yeah, it's not written in C#. The same reason applies.)

0

A 100-element array of some type T encapsulates 100 independent variables of type T. If T happens to be a value type which has a mutable public field of type Q and one of type R, then each element of the array will encapsulate independent variables of types Q and R. The array as a whole will thus encapsulate 100 independent variables of type Q and 100 independent variables of type R; any of those variables may be accessed individually without affecting any other. No collection type other than arrays can allow the fields of structures to be used as independent variables.

If T happened instead to be a class type with public mutable fields of type Q and R, each element of the array holds the only reference, anywhere in the universe, to an instance of T, and if none of the elements of the array will ever be modified to identify an object to which any outside reference exists, then the array will effectively encapsulate 100 independent variables of type Q and 100 independent variables of type R. Other collection types can mimic the behavior of such an array, but if the only purpose of the array is to encapsulate 100 variables of type Q and 100 of type R, encapsulating each pair of variables in its own class object is an expensive way of doing that. Further, using an array or collection of mutable class type creates the possibility that the variables identified by array elements may not be independent.

If a type is supposed to behave like some kind of object, then it should either be a class type or a private-field structure which provides no means of mutation other than replacement. If, however, a type is supposed to behave like a bunch of related-but-independent variables stuck together with duct tape, then one should use a type which is a bunch of variables stuck together with duct tape--an exposed-field struct. Arrays of such types are very efficient to work with, and have very clean semantics. Use of any other type will lead to muddled semantics, inferior performance, or both.

0

One important different is memory allocation. For example, traversing a linked list could result in a lot of cache misses and slower performance, whereas an array represents a contiguous chunk of memory holding multiple instances of some particular data type, and do traversing it in order is more likely to hit the CPU cache.

Of course, an array of object references may not benefit as much from cache hits, since dereferencing could still take you anywhere in memory.

Then there are list implementations such as ArrayList, which implement a list using an array. They're useful primitives to have.

  • 2
    The question specifically asks about the .Net type List<T>, which is not implemented using a linked list, but using an array (it's essentially equivalent to ArrayList<T> in Java). – svick Dec 11 '14 at 2:21
-2

Here's some guidance you can use on when to select Array and when to select List.

  • Use Array when returning from a method.
  • Use List as the variable when you are constructing the return value (inside the method). Then use .ToArray() when returning from the method.

In general, use an Array when you don't intend the consumer to add items to the collection. Use List when you intend the consumer to add items to the collection.

Array is meant for dealing with "static" collections while List is meant for dealing with "dynamic" collections.

  • 2
    The rule you suggest is arbitrary and likely to result in inefficient code that performs unnecessary copying. At the very least you need some form of justification for it. – Jules Dec 11 '14 at 8:53
  • @Jules I've found developer experience to be much more important than micro-optimizations. I never have performance problems on this level. – Daniel Lidström Dec 11 '14 at 9:03
  • I don't see how the developer experience is improved by this rule, however. It requires you to guess what clients of your code are going to want to do with returned values, and makes your code less convenient to use when you get it wrong, and yet I fail to see any advantage at all to it. Performance may be a secondary concern, but I wouldn't sacrifice it to follow a rule that gains nothing. – Jules Dec 11 '14 at 10:18
  • @Jules I guess it comes down to your own preference then. I prefer to treat return values as constants, as such I prefer to use Array instead of List. Nice to hear your thoughts though! – Daniel Lidström Dec 11 '14 at 13:05
  • Have you considered using UmmodifiableLists? – Jules Dec 11 '14 at 15:10

Not the answer you're looking for? Browse other questions tagged or ask your own question.