#c# #linq
#c# #linq
Вопрос:
Например, если у меня есть этот код:
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 (общее количество элементов)?
Спасибо
Ответ №1:
Да, останавливается.
Вы можете ясно увидеть это, переписав код следующим образом:
var result = list.Where(x =>
{
Console.WriteLine("Where: " x);
return x == 2;
})
.Take(2).ToList();
Ответ №2:
list
будет повторяться Where
функцией, возвращая только совпадающие элементы.
Where
будет повторяться Take
, который останавливается после 2 результатов.
Take
полностью повторяется с помощью ToList
Таким образом, конечным результатом является то, что итерация list
останавливается Take
на втором элементе из 2.
Ответ №3:
Вы можете легко проверить это самостоятельно. Давайте проверим 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
) не был принят: исключение не было выдано.
Ответ №4:
Я думаю, что наиболее убедительный (и простой) ответ — посмотреть на исходный код 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
}
}
}
Ответ №5:
Если вы напишете какой-нибудь тестовый код с вашими собственными 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();
}