Reputation: 2100
In C#, what is the fastest way to create and fill a List using an IEnumerable
in terms of time required to write the code for? What about in terms of time required to execute?
My first thought was this:
List<int> list = new List<int>();
foreach(int number in iterator)
list.Add(number);
Is there a faster way?
Upvotes: 3
Views: 3000
Reputation: 9509
When it comes to List<T>
essentially you have 2 approaches, which I am trying to discuss below. For the sake of clarity lets assume, allocation of the List<T>
takes constant time (C), adding an element to the List<T>
also takes constant time.
Create empty List<T>
and populate it
List<int> list = new List<int>(); // C
foreach(int i in iterator)
{
list.Add(i); //n*C
}
as you can see this approach takes n*C + C time, so if you neglect the C the complexity is O(n).
Create List<T>
based on the other IEnumerable<T>
List<int> list = new List<int>(iterator);
however, there is a small difference regards the type of iterator:
if the iterator is ICollection<T>
var array = new T[ICollection.Count] // C ICollection.CopyTo(array) // by MSDN O(n)
if the iterator is IEnumerable<T>
, the same as creating empty and add item by item
So, if you analyze the complexity you cannot avoid O(n) complexity.
BUT...
There is one caveat with the List<T>
growth and capacity which might impact performances. The default List<T>
capacity is 4 and if you add more than 4 elements to the List<T>
the new underlying array, twice of the current size, will be allocated and the elements will be copied...this process will repeat again when we reach the capacity of the List<T>
. You can imagine how much unnecessary copying you might have. In order to prevent this, the best option is to initialize List<T>
with capacity in advance or use the List<T>(ICollection<T>)
ctor.
// benchmark example
var enumerable = Enumerable.Repeat(1, 1000000);
var collection = enumerable.ToList();
Stopwatch st = Stopwatch.StartNew();
List<int> copy1 = new List<int>(enumerable);
Console.WriteLine(st.ElapsedMilliseconds);
st = Stopwatch.StartNew();
List<int> copy2 = new List<int>(collection);
Console.WriteLine(st.ElapsedMilliseconds);
Upvotes: 5