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更重要,但是它呢?
答案 0 :(得分:17)
唯一的区别是List.GetRange
比Take(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)
Take
和GetRange
之间有一个辅音。 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也是有效的。