В 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 54

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)
{
}

Я предпочитаю этот:

theList.Where(itm => itm.Condition).ToList().ForEach(itmFE => { itmFe.DoSomething(); });