[英]Does Take(x) in Linq stops enumerating when taking x objects?
例如,如果我有以下代碼:
public static void Main(string[] args)
{
List<int> list = new List<int>() { 2, 3, 2, 9, 10, 2, 5 };
var out = list.Where(x => x == 2).Take(2).ToList();
}
迭代次數是 3(因為后兩個在索引 2 中)還是 7(元素總數)?
謝謝
是的,停止。
你可以通過如下重寫代碼清楚地看到這一點:
var result = list.Where(x =>
{
Console.WriteLine("Where: " + x);
return x == 2;
})
.Take(2).ToList();
list
將由Where
function 迭代,僅返回匹配項。
Where
將被Take
迭代,在 2 個結果后停止。
Take
完全由ToList
迭代
所以最終的結果是list
的迭代在2的第二項被Take
停止了。
您可以自己輕松檢查。 讓我們測試一下達到9
的假設(即至少迭代了4 個項目):
var result = list
.Where(x => x == 2) // your query under test
.Take(2)
.Select(item => item != 9 // business as usual for the first 3 items
? item // throw exception on the 4th
: throw new Exception("Strange execution: 9 (4th item) has been scanned"))
.ToList(); // materialization executes the query
運行它,你會看到第 4 項( 9
)沒有被取走:沒有拋出異常。
我認為最有說服力(也是最簡單)的答案是查看TakeIterator
在調用Take
時運行的源代碼:
static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> source, int count)
{
if (count > 0) {
foreach (TSource element in source) {
yield return element;
if (--count == 0) break; // Yep, it stops after "count" iterations
}
}
}
如果你用自己的 IEnumerable 和 IEnumerator 編寫一些測試代碼,就很容易看出會發生什么。
class MyCollection : IEnumerable<int>
{
public List<int> Data {get; set;} = new List<int>() { 2, 3, 2, 9, 10, 2, 5 };
public IEnumerator<int> GetEnumerator()
{
return new MyEnumerator()
{
Data = this.Data,
};
}
}
和枚舉器:
class MyEnumerator : IEnumerator<int>
{
private int index = -1;
public List<int> Data {get; set;}
public void Reset()
{
this.index = -1;
}
public bool MoveNext()
{
++this.index;
return this.index < this.Data.Count;
}
public int Current
{
get
{
int returnValue = this.Data[this.index];
Debug.WriteLine("[{0}] {1}", this.index, returnValue);
return returnValue;
}
}
}
測試代碼:
void Main()
{
MyCollection collection = new MyCollection();
var out = collection.Where(x => x == 2).Take(2).ToList();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.