В LINQ + по каждому объекту против + если
мне нужно перебирать список объектов, делать что-то только для объектов, которые имеют свойство boolean значение true. Я с уверенностью сказать, что этот код
foreach (RouteParameter parameter in parameters.Where(p => p.Condition))
{ //do something }
и этот код
foreach (RouteParameter parameter in parameters)
{
if !parameter.Condition
continue;
//do something
}
первый код, очевидно, чище, но я подозреваю, что он будет перебирать список дважды - один раз для запроса и один раз для foreach. Это не будет огромный список, поэтому я не слишком беспокоюсь о производительности, но идея зацикливания дважды просто ошибки меня.
вопрос: есть ли чистый/красивый способ написать это без цикла дважды?
4 ответа:
Джон Скит иногда делает демонстрацию LINQ в реальном времени, чтобы объяснить, как это работает. Представьте, что у вас на сцене три человека. Слева у нас есть один парень, у которого есть перетасованная колода карт. В середине у нас есть один парень, который только передает красные карточки, а справа у нас есть парень, который хочет карты.
парень справа тычет парня в середине. Парень в середине тычет парня слева. Парень на левой руке парень в середине карты. Если он черный, то парень в середине бросает его на пол и тычет снова, пока он не получает красную карточку, которую он затем передает парню справа. Затем парень справа снова тычет парня в середине.
Это продолжается до тех пор, пока у парня слева не закончатся карты.
колода не была пройдена от начала до конца более одного раза. тем не менее, и парень слева, и парень в середине обрабатывали 52 карты, а парень справа обрабатывал 26 карт. Было всего 52 + 52 + 26 операции по картам, но палуба была только петля через один раз.
ваша версия " LINQ "и версия" continue " - это одно и то же; если бы у вас было
foreach(var card in deck) { if (card.IsBlack) continue; ... use card ...
затем есть 52 операции, которые извлекают каждую карту из колоды, 52 операции, которые проверяют, является ли каждая карта черной, и 26 операций, которые действуют на красную карту. Одно и то же.
большинство операторов Linq, таких как
Where
создать отложенное и ленивое выполнение. В вашем примере список будет повторяться только один раз, потому что перечислитель, сидящий за IEnumerable, возвращаетсяWhere
будет перечислять список до тех пор, пока он не найдет элемент, соответствующий предикату, дает его и будет продолжаться только тогда, когда он запрашивается для следующего элемента.С точки зрения кода, я бы предпочел вариант, используя where, хотя это может быть утверждал, что вы можете объявить локальный для
parameters.Where(p => p.Condition)
.Джон Скит Edulinq серия настоятельно рекомендуется, чтение некоторых бит этого должно помочь вам в понимании операторов LINQ.
на самом деле, это не "цикл дважды.- Это
.Where
статья использует отложенное выполнение. Другими словами, практически никакая работа не выполняется, когда вы называете.Where
, но когда вы повторяете результат, он будет повторять исходный список и проходить только через элементы, соответствующие вашему условию. Если вы думаете об этом с точки зрения того, как выполняется код, вы эффективно делаете это:Func<Parameter, bool> matchesCondition = p => p.Condition; foreach(var parameter in parameters) { if(matchesCondition(parameter)) { ... } }
что касается стиля, я лично предпочитаю что-то вроде:
var matchingParameters = parameters.Where(p => p.Condition); foreach(var parameter in matchingParameters) { }