list.Take(100).ToList()与list.GetRange(0,100)

时间:2015-09-21 09:05:28

标签: c# linq

List<AttendeeInfo> attendees = new List<AttendeeInfo>();
foreach ...
// Error: "There are too many target users in the email address array"
// for more than 100 attendees. So take the first 100 attendees only.
if(attendees.Count > 100) attendees = attendees.GetRange(0,100);
// or
if(attendees.Count > 100) attendees = attendees.Take(100).ToList();

由于我处理的列表总是超过100,并且总是占用前100,因此最明显的差异(评估策略,跳过的可能性,抛出错误)并不是很有趣。

但也许你可以清楚地了解究竟是什么&#34;在源列表中创建一系列元素的浅层副本&#34;手段。它听起来真的很贵,比Take更重要,但是它呢?

5 个答案:

答案 0 :(得分:17)

唯一的区别是List.GetRangeTake(n).ToList()更有效,因为它已经知道新列表的大小,而LINQ方法不知道它的大小。

所以ToList枚举序列并使用加倍算法将项添加到新列表中,从而连续增加后备阵列。 List.GetRange可以预先创建具有正确初始大小的正确列表,然后使用Array.Copy将源列表的子集复制到新列表[source]。

答案 1 :(得分:6)

速度要快得多。看看这个:

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);

经过的时间:

List.GetRange():0.149 s

List.Take().ToList():3.625 s

答案 2 :(得分:3)

以下是 GetRange 实施:

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;
}

这是 Take 实施

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;
            }
        }
    }
}

加上ToList只是:

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    return new List<TSource>(source);
}

List构造函数:

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);
            }
        }
    }
}

您可以立即注意GetRange

Take

的价格是多少https://www.google.com/jsapi

答案 3 :(得分:1)

List.Take(100).ToList(),如果你不知道列表中的元素数量会更合适。如果它小于100,它只需要可用的那些。 使用它更灵活。

另一方面, List.GetRange(0,100)假设列表中的元素数量超过100.但是会出现此错误***

  

偏移和长度超出数组范围或计数更大   比从索引到源头的元素数量   集合

***。 如果元素的数量小于指定的范围。

对我来说,我会说 List.Take(100).ToList()更强泛型,因为它不会限制使用。

答案 4 :(得分:1)

TakeGetRange之间有一个辅音。 Take会懒惰地进行评估,直到您迫使其转移到ToList()中为止。这可以改变行为。

考虑伪代码。

List<int> myList = new List<int>() {1,2,3,4,5,6};
IEnumerable<int> otherList = myList.Take(3);  // {1,2,3};
myList.RemoveRange(0,3);
// myList = {4, 5, 6}
// otherList = {4, 5, 6}

现在将此示例更改为以下代码。

List<int> myList = new List<int>() {1,2,3,4,5,6};
IEnumerable<int> otherList = myList.Take(3).ToList();  // {1,2,3};
myList.RemoveRange(0,3);
// myList = {4, 5, 6}
// otherList = {1, 2, 3}

执行ToList()可以更改Take或GetRange的行为,具体取决于下一步要使用的操作。使用GetRange总是更容易,因为它不会引起任何未知的错误。

GetRange也是有效的。