簡體   English   中英

Linq 中的 Take(x) 是否在獲取 x 個對象時停止枚舉?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM