none
List<> vs array[] RRS feed

  • Question

  • few weeks ago i discovered the List <>  of c# (i know am slowSmile and since then, i found myself using List everywhere i used to use arrays. and the deal is that am sure that each one has its own advantage, but i just cant see what is better with array then List?

     

    can anyone tell me if using List everywhere is good, and if not then where should i use the other?

     

    thanks.

    • Edited by Brent Serbus Friday, May 30, 2008 12:23 AM fixing encoding
    Friday, March 30, 2007 12:10 PM

Answers

  • I would say it depends what you're trying to accomplish. Generally, however, my opinion is that you have access to a great framework that does a lot of hard work for you so use it (ie. use List<> instead of array).

     

    Have a look at the members on offer to you by a class like List<> and you'll see what I mean: in addition to not having to worry as much about array capacity and index out of bounds exceptions, List and other ICollection/IList classes give you methods like Add, Remove, Clear, Insert, Find, etc that are infinitely helpful. I also believe

     

    Code Snippet
    myList.Add (myWidg);

     

     is a lot nicer to read and maintain than

     

    Code Snippet
    myArr [i] = myWidg;

     

     

    If you're worried about performance, don't until you're sure it's a problem. Read Code Complete 2e for a great introduction to performance tuning and why not to do it. :-)

     

    Cheers,

    Michhes

    Monday, April 2, 2007 1:13 AM
  • Kind of...

    You need to know the size of an array at the time that it is created, but you cannot change its size after it has been created.

    So, it uses dynamic memory allocation for the array at creation time. (This differs from static memory allocation as used for C++ arrays, where the size must be known at compile time.)

    A list can grow dynamically AFTER it has been created, and it has the .Add() function to do that.
    Friday, March 30, 2007 2:11 PM

All replies

  • Hi,

    AFAIK,List works based dynamic memory allocation and array works based static memory allocation.So if we know the number of elements to be stored ,we can go for array.Otherwise we can go for list.

     

    Thanx,

    Ch.T.Gopi Kumar.

    Friday, March 30, 2007 1:09 PM
  • Kind of...

    You need to know the size of an array at the time that it is created, but you cannot change its size after it has been created.

    So, it uses dynamic memory allocation for the array at creation time. (This differs from static memory allocation as used for C++ arrays, where the size must be known at compile time.)

    A list can grow dynamically AFTER it has been created, and it has the .Add() function to do that.
    Friday, March 30, 2007 2:11 PM
  •  Vbeginer.net wrote:

    few weeks ago i discovered the List <> of c# (i know am slow and since then, i found myself using List everywhere i used to use arrays. and the deal is that am sure that each one has its own advantage, but i just cant see what is better with array then List?

    can anyone tell me if using List everywhere is good, and if not then where should i use the other?

    thanks.



    This is merely esoteric but if one needs to send something through a params method call such as

    public void Columns(params string[] ColumnNames) { ... }

    and one wants to do the same with a generic list such as:

    public void Columns(params List<string> items ) { ... }

    the List<...> will not work. See my rant here params parameter must be a single dimensional array - (It is! Tell me it isn't!)
    Friday, March 30, 2007 7:26 PM
    Moderator
  •  Matthew Watson wrote:
    Kind of...

    You need to know the size of an array at the time that it is created, but you cannot change its size after it has been created.

    So, it uses dynamic memory allocation for the array at creation time. (This differs from static memory allocation as used for C++ arrays, where the size must be known at compile time.)

    A list can grow dynamically AFTER it has been created, and it has the .Add() function to do that.
    There's Array.Resize() but that changes the reference after copying it...
    Saturday, March 31, 2007 12:43 AM
    Moderator
  • params is hardly esoteric; and what do params have to do with the OPs question?
    Saturday, March 31, 2007 12:46 AM
    Moderator
  • I would say it depends what you're trying to accomplish. Generally, however, my opinion is that you have access to a great framework that does a lot of hard work for you so use it (ie. use List<> instead of array).

     

    Have a look at the members on offer to you by a class like List<> and you'll see what I mean: in addition to not having to worry as much about array capacity and index out of bounds exceptions, List and other ICollection/IList classes give you methods like Add, Remove, Clear, Insert, Find, etc that are infinitely helpful. I also believe

     

    Code Snippet
    myList.Add (myWidg);

     

     is a lot nicer to read and maintain than

     

    Code Snippet
    myArr [i] = myWidg;

     

     

    If you're worried about performance, don't until you're sure it's a problem. Read Code Complete 2e for a great introduction to performance tuning and why not to do it. :-)

     

    Cheers,

    Michhes

    Monday, April 2, 2007 1:13 AM
  •  michhes wrote:

    .... I also believe

     

    myList.Add (myWidg);

     

    is a lot nicer to read and maintain than

     

    myArr = myWidg;

     

    .....

    That is, an implemented method is always worse than an assignment operation  ?

    Where is the point ?

    Monday, April 2, 2007 1:43 AM
  •  minic wrote:
     michhes wrote:

    .... I also believe

     

    myList.Add (myWidg);

     

    is a lot nicer to read and maintain than

     

    myArr = myWidg;

     

    .....

    That is, an implemented method is always worse than an assignment operation  ?

    Where is the point ?

    you reverse the two subjects which contradicts what s/he is trying to say.

    I also agree the AddmyWidg) looks neater and natural than the here=there 

     

    That's just a thought, Marrylong 

     

    Monday, April 2, 2007 2:16 AM
  •  Peter Ritchie wrote:
    There's Array.Resize() but that changes the reference after copying it...

    Yes, i.e. it's the same as manually creating a new array and copying the elements one-by-one from the old array into the new one.

    Monday, April 2, 2007 8:52 AM
  •  Matthew Watson wrote:
     Peter Ritchie wrote:
    There's Array.Resize() but that changes the reference after copying it...

    Yes, i.e. it's the same as manually creating a new array and copying the elements one-by-one from the old array into the new one.

    Actually, it's slightly more efficient than copying one-by-one; but a copy does occur.
    Monday, April 2, 2007 1:27 PM
    Moderator
  • True, it's faster because it uses Array.Copy() to copy the elements, but I assume it's still an O(N) operation.


    Monday, April 2, 2007 1:32 PM
  •  Matthew Watson wrote:
    True, it's faster because it uses Array.Copy() to copy the elements, but I assume it's still an O(N) operation.
    Correct, it's documented as being O(n).
    Monday, April 2, 2007 1:53 PM
    Moderator
  • List<> is nice, however, the framework guidelines suggest using it internally, and only exposing arrays as parameters/return values.

     

    List<> is especially nice when doing recursive calls that return data because you can use AddRange to add to itself. E.g.:

     

    private List<string> RecursiveCall(Things things)

    {

      List<string> thingsList = new List<string>();

     

      foreach (Thing thing in things)

      {

        thingsList.Add(thing.ToString());

        returnValue.AddRange(RecursiveCall(thing.Things));

      }

     

      return thingsList;

    }

     

    (Assuming a hierarchical list of some sort here that you're trying to flatten out or whatever where each Thing could have a collection of Thing objects in a property called Things and the leaf nodes have zero item Things properties.)

    Monday, April 2, 2007 10:21 PM
  •  Robert C. Barth wrote:

    List<> is nice, however, the framework guidelines suggest using it internally, and only exposing arrays as parameters/return values

     

    Very true... generics are new in .NET 2.0 and if there's no need to expose the list as a generic list, then why do it, right?

     

    That said, it's dead easy to simply derive List (or some other generic collection) and create your own, strongly-typed business object collections that can then be exposed for public consumption:

     

    Code Snippet

    public class UriCollection : List<Uri>
     {
       // No implementation
     }

     

    The result is an object that still looks like an old-school collection until closer inspection.

    Tuesday, April 3, 2007 1:28 AM
  •  michhes wrote:
     Robert C. Barth wrote:

    List<> is nice, however, the framework guidelines suggest using it internally, and only exposing arrays as parameters/return values

     

    Very true... generics are new in .NET 2.0 and if there's no need to expose the list as a generic list, then why do it, right?

     

    That said, it's dead easy to simply derive List (or some other generic collection) and create your own, strongly-typed business object collections that can then be exposed for public consumption:

    Code Snippet

    public class UriCollection : List<Uri>
     {
       // No implementation
     }

     

    The result is an object that still looks like an old-school collection until closer inspection.

    Thursday, May 29, 2008 4:49 PM
  • These data structures have different purposes.

     

    Array[] is a fixed size datastructure you would use when you pass around to another components and you do not want them to change its contents.

     

    On the contrary you would use List<> to hold dynamix data and can change its contents easily.

     

     

     

    Thursday, May 29, 2008 4:52 PM
  • Was looking for an answer of how best to mirror a dataset which contained child tables.  Considered options were list<> and array[].

    Having read every reply, it seemed much of the discussion focused on the aesthetics of mylist.add(newitem) vrs myarray[++iterator] = newitem;

    One respondent discussed the advantages of using recursion as a means of fulfilling the unknown nodes and sub-nodes problem (like directory navigation). 

    Automatic memory management for list was also discussed in several posts.   In these days of managed code all of it is a lot easier, regardless of what is used.  As for speed, who knows?  My guess is you could copy a fairly large array in the amount of time required .add but since even the indigenous data types are classes, there may be little advantage to the underlying code footprint and speed of arrays over lists.

    HOWEVER, no one discussed the direct versus indirect access of arrays and lists. 

    For instance, if I wanted to know if the 3rd element of my array.isvalid attribute is true it's 

        if(myarray[2].isvalid) //"yes" code goes here

    The access time is very quick

    For my list example, I must use a foreach to access (essentially randomly) the members of the list and must have a means of identifying the row I want with a contained attribute (ie.  .myID) 

        foreach(item in mylist)  //terseness intentially avoided for readability
       {
         if(item.myID == 2)
         {
            if(item.isvalid) //"yes code goes here
         }
       }

    Lists inherit some helper functions that will make life easier and offer alternatives to the prior construct.  Check out FindAll() and Sort() for more information.  Additionally, Linq queries work against lists. 

    On the positive note, that basic batch process structure works for just about anything I'd care to do to my list.  No specific iterator loops for this or that just the same old block of code with the active code changed as needed. 

    We coders hate so much to copy-n-paste. //mylist.add(tongue_in_cheek)

    It is worth noting that, with the block methods, the access time could be long depending on the sample size.  In our case we're dealing with 50,000 objects containing as many as 10 child rows.  My guess is that the FindAll does much of the same, just does it in the background.

    There is no iteration penalty with arrays but knowing that you're looking for element #2 may be "non-trivial" in some cases.

    I haven't looked to see if .Net has associative lists yet (was that MFC that had associative arrays?, kind of forget) whereby you could access the "Fred" element of an associative array.  In the background, the framework q-sorted the indeci for you.  Pretty slick methought.

    A big thanks to the authors who noted the param details!  That was news to me.

    Wednesday, January 14, 2009 3:57 PM
  • Hi Shooky
    You DONT need to iterate through the list to get the Nth item.
    Accessing list items is an O(1) operation just like accessing an item in an array eg:
    if (myNameList[3] == "Hello") doSomeThing();

    A List<> is in fact a nice wrapper on top of an array.
    When you create a list you may specify the size of the underlaying array in the constructor (see List.Capacity property).  The default capacity is 2 (I think).
    What makes the list dynamic is that when/if you add more items than the underlaying array can contain (ie List.Count == List.Capacity) the list automatically reallocates the underlaying array to double size (doubling the array size each time more space is required alleviates the reallocation overhead when adding many items to the list - I had some theory about that at school).
    Add method documentation: If Count is less than Capacity, this method is an O(1) operation. If the capacity needs to be increased to accommodate the new element, this method becomes an O(n) operation, where n is Count.

    Generally I see no reason not to favor lists over arrays. If you know the amount of items you'll be adding to your list (as you would if you were to allocate an array) then specify that in the list constructor - that way there will be no reallocation overhead when populating the list.
    One small disadvantage of using a list is that you need to initialize its content before you can access it content. eg:

                List<bool> myBoolList = new List<bool>(4);
                for (int i = 0; i < myBoolList.Capacity; i++)
                    myBoolList.Add(false);
    
                if (myBoolList[1])
                    DoThis();
                else
                    DoThat();



    as opposed to:

                bool[] myBoolArray = new bool[4];
                if (myBoolArray[1])
                    DoThis();
                else
                    DoThat();



    If you need to pass the list items to a method that requires an array (eg params object) then there's always List<>.ToArray (which is O(n) would have been nice if we had direct access to the underlaying array).
    But methods that accept arrays can be rewritten to accept IList<MyType> - that way you can throw Lists and Arrays at them - you wont brake existing code. Now it’s up to the caller to choose which data structure she prefers.
    If your method simply needs to iterate through the items then you can make do with ICollection<MyType> - or even IEnumerable<MyType> if you dont need to know the size of the list/array up front.
    This way the data can come from a wider range of data structures eg. the Keys of a Dictionary:

            class Customer
            { }
    
            private void foo(IEnumerable<string> names)
            {
                //With IEnumerable I have no idea how many items there are. 
                //All I can do is iterate through them.
                string s2;
                foreach (string name in names)
                    s2 = AppendSomeText(name);
            }
            
            public void TestLists()
            {
                Dictionary<string, Customer> myDic = new Dictionary<string, Customer>();
                myDic.Add("Klaus", new Customer());
                myDic.Add("Jensen", new Customer());
                foo(myDic.Keys);
            }
    



     

     


    Klaus Bjørn Jensen
    Friday, September 4, 2009 1:58 PM
  • Generally I see no reason not to favor lists over arrays. 

                List<bool> myBoolList = new List<bool>(4);


    The primary reason one use a generic list over an array is for type safety and removal from the overhead of boxing. The second is the fact that one doesn't have to know the size of the array beforehand. The statement shown in your quote is not typical of C# code. Frankly I don't think I have ever specified a size...I might specify actuals though...

    List<bool> mybools = new List<bools>() { true, false, true, false };


    William Wegerson (www.OmegaCoder.Com)
    Sunday, September 6, 2009 6:24 PM
    Moderator
  • The primary reason one use a generic list over an array is for type safety and removal from the overhead of boxing.
    If by "array" you mean things like this:

    int[] array = new int[1000];

    Then there is NO boxing overhead for accessing elements of such an array.

    Monday, September 7, 2009 8:38 AM
  • Generally I see no reason not to favor lists over arrays.

    I think the fact that access to array elements is much faster than access to list elements is pretty compelling.

    Consider the code below. When I run it on my PC (release mode) its output is:

    Trial 1
    Array took 00:00:00.1022744
    List took 00:00:00.1895158
    Array was 1.85301307071955 times faster.
    Trial 2
    Array took 00:00:00.1002861
    List took 00:00:00.1889172
    Array was 1.88378249827244 times faster.
    Trial 3
    Array took 00:00:00.1006373
    List took 00:00:00.1891501
    Array was 1.87952280118803 times faster.
    Trial 4
    Array took 00:00:00.1014679
    List took 00:00:00.1891592
    Array was 1.86422701169532 times faster.

    Array element access is nearly twice as fast as list element access. That can be significant in some cases!

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                Stopwatch sw = new Stopwatch();
    
                const int iters = 1000;
                const int size = 100000;
    
                List<int> list = new List<int>(size);
    
                for (int i = 0; i < size; ++i)
                {
                    list.Add(0);
                }
    
                int[] array = new int[size];
    
                for (int trial = 1; trial <= 4; ++trial)
                {
                    Console.WriteLine("Trial " + trial);
    
                    sw.Reset();
                    sw.Start();
    
                    for (int i = 0; i < iters; ++i)
                    {
                        Sum(array);
                    }
    
                    sw.Stop();
                    TimeSpan arrayTime = sw.Elapsed;
                    Console.WriteLine("Array took " + arrayTime);
    
                    sw.Reset();
                    sw.Start();
    
                    for (int i = 0; i < iters; ++i)
                    {
                        Sum(list);
                    }
    
                    sw.Stop();
                    TimeSpan listTime = sw.Elapsed;
                    Console.WriteLine("List took " + listTime);
                    Console.WriteLine("Array was " + (listTime.TotalSeconds/arrayTime.TotalSeconds) + " times faster.");
                }
            }
    
            static int Sum(int[] array)
            {
                int result = 0;
    
                for (int i = 0; i < array.Length; ++i)
                {
                    result += array[i];
                }
    
                return result;
            }
    
            static int Sum(List<int> list)
            {
                int result = 0;
    
                for (int i = 0; i < list.Count; ++i)
                {
                    result += list[i];
                }
    
                return result;
            }
        }
    }
    

    Monday, September 7, 2009 8:49 AM
  • Hi,

    To add my 2 cents worth... it depends on what you mean by everywhere. Typically if you are exposing a public method or property you should have a return type of either an IList or IEnumerable instead of List, but you can use list internally, i.e

    public IList<string> GetList()
    {
      List<string> returnValue = new List<string>();
      
      returnValue.Add("Test");

      return returnValue;
    }

    or

    public IEnumerable<string> GetList()
    {
      List<string> returnValue = new List<string>();
      
      returnValue.Add("Test");

      return returnValue;
    }

    In this case, if you change your mind about what kind of list you want to return later you can do so without breaking the interface of your class. For example, if you decided to change your code so it used a SortedList<string> like this, you can do so without breaking the signature of the GetList method (although you might still alter behaviour of the list which could cause issues elsewhere);

    public IList<string> GetList()
    {
      SortedList<string> returnValue = new SortedList<string>();
      
      returnValue.Add("Test");

      return returnValue;
    }

    In terms of choosing between IList and IEnumerable, the usual advice is to choose the one that has the minimum set of functionality you expect your callers to want. If you expect your caller is just going to enumerate the items you return, IEnumerable is ok, but if you think they want to be able to add and remove items, get the count, insert items in the middle of the list etc. then use IList. The choice of return type is more important when you're building libraries, frameworks or other public API's, if the method is private, internal to your application or otherwise not intended to be consumed by 3rd party code then it's less important and you can stil return List<string>, but even then it might make it more difficult to refactor your code later. Returning IList etc. instead of List is a rule enforced by FxCop and VS Code Analysis, so it's probably good practice.

    Also, accessing arrays is possibly a little faster, but unless performance is absolutely critical to a piece of code it usually makes little difference in terms of real-world performance.
    Monday, September 7, 2009 8:59 AM
  • Also, accessing arrays is possibly a little faster, but unless performance is absolutely critical to a piece of code it usually makes little difference in terms of real-world performance.
    If you start using IEnumerable, it is no longer twice as slow - things become 10 times slower!

    If you take my sample code above and replace the second Sum() function with this:

            static int Sum(IEnumerable<int> sequence)
            {
                int result = 0;
    
                foreach (int value in sequence)
                {
                    result += value;
                }
    
                return result;
            }
    
    The results are then:

    Trial 1
    Array took 00:00:00.1291601
    List took 00:00:01.3436711
    Array was 10.4031438501519 times faster.
    Trial 2
    Array took 00:00:00.1030116
    List took 00:00:01.3141407
    Array was 12.757210838391 times faster.
    Trial 3
    Array took 00:00:00.1041967
    List took 00:00:01.2333304
    Array was 11.8365591232736 times faster.
    Trial 4
    Array took 00:00:00.1045778
    List took 00:00:01.3032508
    Array was 12.462021576281 times faster.

    Of course, in most cases this makes no difference. But if you're writing library code, you can't know the context in which things are being called; in particular, you can't know how time-critical things are. In such cases, you should choose the performant code.

    We have noticably speeded up things in our programs by avoiding IEnumerable in many places. Making something an order of magnitude faster is definitely noticable!

    Monday, September 7, 2009 10:43 AM
  • The primary reason one use a generic list over an array is for type safety and removal from the overhead of boxing.

    Then there is NO boxing overhead for accessing elements of such an array.

    My bad. That is correct. I was thinking in terms of the arraylist.

    Performance Guideline: Use Generics To Eliminate the Cost Of Boxing, Casting and Virtual calls
    William Wegerson (www.OmegaCoder.Com)
    Friday, September 11, 2009 2:13 PM
    Moderator
  • I have being asking the same question.

    Use Array for speed of access.

    User List for speed of insertion.

    --Jeff

    Wednesday, July 20, 2011 4:48 PM
  • incorrect you can create an array in C# and later as you like add items.
    the person who asked it asked it for c# not for c++
    Friday, June 29, 2012 5:45 PM
  • incorrect you can create an array in C# and later as you like add items.
    the person who asked it asked it for c# not for c++
    Show me the code that does this. :)

    (not using Array.Resize(), of course, since that's not "adding" to the array - it's creating a new array and copying the old array to it)
    Monday, July 2, 2012 7:54 AM
  • You need to know the size of an array at the time that it is created, but you cannot change its size after it has been created.

    This is incorrect, this is a dynamic array:

    string[] gsNote {};

                            if (words[0] == "note") {

                                Array.Resize(ref gsNote, gsNote.Length + 1);

                                  gsNote[gsNote.Length - 1] = sParseDoubleQuotes(words[1]);

                            }

    Wednesday, November 23, 2016 11:45 PM