list.Take(100).ToList() vs. list.GetRange(0,100)
The only difference is that List.GetRange
is more efficient than Take(n).ToList()
since it already knows the size of the new list whereas the LINQ methods don't know it's size.
So ToList
enumerates the sequence and adds the items to a new list with a doubling algorithm increasing the backing array consecutively. List.GetRange
can create the proper list with the right initial size beforehand and then uses Array.Copy
to copy the subset of the source list into the new list [source].
It is much more faster. Check this out:
var list = Enumerable.Range(0, 1000).ToList();
var stopwatch = new Stopwatch();
stopwatch.Start();
for(var i=0; i<1000000; i++)
{
var c = list.GetRange(0, 100);
}
Console.WriteLine(stopwatch.Elapsed);
stopwatch.Restart();
for (var i = 0; i < 1000000; i++)
{
var c = list.Take(100).ToList();
}
Console.WriteLine(stopwatch.Elapsed);
Elapsed time:
List.GetRange()
: 0.149 s
List.Take().ToList()
: 3.625 s
Here is GetRange
implementation:
public List<T> GetRange(int index, int count)
{
if (index < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
}
if (count < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
}
if ((this._size - index) < count)
{
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
}
List<T> list = new List<T>(count);
Array.Copy(this._items, index, list._items, 0, count); // Implemented natively
list._size = count;
return list;
}
And this is Take
Implementation
public static IEnumerable<TSource> Take<TSource>(this IEnumerable<TSource> source, int count)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return TakeIterator<TSource>(source, count);
}
private static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> source, int count)
{
if (count > 0)
{
foreach (TSource iteratorVariable0 in source)
{
yield return iteratorVariable0;
if (--count == 0)
{
break;
}
}
}
}
Plus ToList
that simply does:
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return new List<TSource>(source);
}
And List
constructor:
public List(IEnumerable<T> collection)
{
if (collection == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
}
ICollection<T> is2 = collection as ICollection<T>;
if (is2 != null)
{
int count = is2.Count;
if (count == 0)
{
this._items = List<T>._emptyArray;
}
else
{
this._items = new T[count];
is2.CopyTo(this._items, 0);
this._size = count;
}
}
else
{
this._size = 0;
this._items = List<T>._emptyArray;
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
while (enumerator.MoveNext())
{
this.Add(enumerator.Current);
}
}
}
}
You can note immediately how much GetRange
is cheaper against Take