2010-02-02 2 views
1

относительно linq к объектам, если я использую .Where (x => x ....), а затем сразу же использовать .SkipWhile (x => x ...), это повлечет за собой потому что я перебираю коллекцию дважды?Сочетание операторов LINQ для эффективности

Должен ли я найти способ поместить все в предложение Where или в предложение SkipWhile?

ответ

2

Использование Where и SkipWhile не приводит к «переходу коллекции дважды». LINQ to Objects работает на модели pull. Когда вы перечисляете комбинированный запрос, SkipWhile начнет запрашивать его источник для элементов. Его источником является Where, поэтому это приведет к тому, что Where начнет запрашивать исходный код в свою очередь для элементов. Таким образом, SkipWhile увидит все элементы, которые передают предложение Where, но они получают их как есть. Результатом является то, что LINQ выполняет foreach над исходной коллекцией, возвращая только элементы, которые передают фильтры Where и SkipWhile, и это включает только один проход по коллекции.

Возможно, существует тривиальная потеря эффективности, поскольку задействованы два итератора, но вряд ли они будут значительными. Вы должны написать код, который будет чистым (как вы это делаете в данный момент), и если вы подозреваете, что чистая версия вызывает проблему с производительностью, то измерьте, чтобы убедиться, что, и только затем попытайтесь объединить предложения.

1

Нет, есть (по существу) штраф за исполнение. Вот что такое ленивое (отложенное) исполнение.

2

Как и в большинстве случаев, ответ зависит от того, что вы делаете. Если у вас несколько элементов, на которых работает тот же объект, вероятно, стоит их комбинировать с & &.

Большинство операторов LINQ не будут перебирать всю коллекцию для каждого оператора, они просто обрабатывают один элемент и передают его на следующий оператор. Существуют исключения из этого, такие как Reverse и OrderBy, но обычно, если вы используете Where и SkipWhile, например, у вас будет цепочка, которая обрабатывает один элемент за раз. Теперь ваш первый оператор Where может явно отфильтровать некоторые элементы, поэтому SkipWhile не будет видеть элемент до тех пор, пока он не пройдет через предыдущий оператор.

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

7

Незначительная неэффективность из-за объединения итераторов вместе, но это будет очень незначительно. (В частности, хотя каждый соответствующий элемент будет замечен обоими операторами, они не будут буферизированы или что-то в этом роде. LINQ to Object не собирается создавать новый список всех совпадающих элементов и затем запустите SkipWhile over это.)

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

2

Вы не, переходя через коллекцию дважды, когда используете Where и SkipWhile.

Метод Where будет течь свой выход к SkipWhile методу одного элемента за один раз, и также способ SkipWhile будет течь свой выходной сигнал на любой последующий метод одного элемента за один раз.

(Небольшие накладные расходы будут вызваны тем, что компилятор генерирует отдельные объекты итератора для каждого метода за кулисами. Но если я был обеспокоен накладными расходами итераторов, генерируемых компилятором, то я, вероятно, не использовал бы LINQ в первом место.)