Одинаково ли количество обрабатываемых элементов ввода независимо от того, когда вызывается оператор Linq-to-Objects? - PullRequest
0 голосов
/ 06 декабря 2011

Даже если оператор Select вызывается до оператора Take, лямбда-выражение будет вызываться только для первых двух элементов ввода:

        string[] count = { "one ", "two ", "three ", "four ", "five ", "six " };
        IEnumerable<int> results = count.Select(item =>
                               {
                                      Console.WriteLine(item);
                                      return item.Length;
                               }).Take(2); 
        foreach (int i in results);

OUTPUT:

one two 

a) Если предположить, что мы объединяем несколько стандартных операторов запросов Linq-to-Objects, разве порядок, в котором оператор Take вызывается, никогда не важен?Таким образом, не имеет значения, будет ли Take вызываться первым или последним, поскольку число входных элементов, для которых будет вызываться лямбда-выражение, всегда одинаково?-Объединяет стандартные операторы запросов вместе, есть ли другие операторы Linq-to-Objects, где порядок их вызова не влияет на количество элементов ввода, для которых вызывается лямбда-выражение?

Спасибо

Ответы [ 2 ]

1 голос
/ 06 декабря 2011

Заказ важен, но его исполнение обычно откладывается и, несомненно, оптимизируется.Если ваши утверждения / наблюдения были правильными, то добавление ToList () перед Take () не повлияет на вывод, но это повлияет.Вызов ToList () действует для принудительного полного перечисления перед Take () и приводит к тому, что лямбда Select вызывается для всех элементов.

Урок здесь не полагается на оптимизацию для корректности.

string[] count = { "one ", "two ", "three ", "four ", "five ", "six " }; 
IEnumerable<int> results = count.Select(item => 
                           { 
                                      Console.WriteLine(item); 
                                      return item.Length; 
                           })
                          .ToList()
                          .Take(2);
1 голос
/ 06 декабря 2011

Операторы запросов, как правило, продвигают только столько шагов вперед в исходной коллекции, сколько им нужно для получения необходимого количества выходных результатов.

В вашем примере Take() потребуется только 2 элемента из Select(), поэтомуэто все, что будет произведено Select().Select(), вероятно, реализовано примерно так (взято из блога Джона Скита :

private static IEnumerable<TResult> Select<TSource, TResult>( 
    this IEnumerable<TSource> source, 
    Func<TSource, TResult> selector) 
{ 
    foreach (TSource item in source) 
    { 
        yield return selector(item); 
    } 
}

Операторам сортировки и группировки потребуется создать полный набор результатов, прежде чем можно будет что-либо вернуть (например, OrderBy()).

Пока вы не используете упорядочение, группировку, фильтрацию (например, с помощью Where() или Skip()) или любой другой оператор, изменяющий количество элементов в последовательностине должно иметь значения, куда в цепи вы положили Take().

...