Напишите лямбда-выражение для выполнения вычисления в списке - PullRequest
3 голосов
/ 04 сентября 2011

У меня есть список / IEnumerable объектов, и я хотел бы выполнить вычисления для некоторых из них.

например. myList.Where (е => f.Calculate == истина) .calculate ();

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

В списке содержатся «строки», в которых сумма указана в Месяце 1, Месяце 2, Месяце 3 ... Месяце 12, Годе 1, Годе 2, Годе 3-5 или «Долгосрочной перспективе». Большинство линий являются фиксированными и всегда попадают в один из этих месяцев, но некоторые «строки» рассчитываются на основе их «Даты погашения».

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

Итак, я хотел бы вызвать метод, который работает только на рассчитанных строках и помещает правильную сумму в правильный «месяц». Я не беспокоюсь о логике вычислений, а скорее о том, как превратить это в легко читаемый метод, который обновляет список, в идеале не возвращая новый список.

[Можно ли написать метод лямбда-расширения, чтобы выполнить как вычисление, так и где - или это перебор в любом случае, так как Where () уже существует?]

Ответы [ 3 ]

5 голосов
/ 04 сентября 2011

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

for (int i=0;i<list.Count;++i)
{
     if (list[i].ShouldCalculate)
         list[i] = list[i].Calculate();
}

Это, по крайней мере, гораздо более очевидно, что оно будет обновляться.LINQ рассчитывает выполнить запрос , не изменяя данные.


Если вы действительно хотите использовать LINQ для этого, вы можете - но ему все равно потребуется копия, есливы хотите иметь List<T> в качестве результатов:

myList = myList.Select(f => f.ShouldCalculate ? f.Calculate() : f).ToList();

Это вызовет ваш метод Calculate() при необходимости и скопирует оригинал, когда он не нужен.Для создания нового List<T> требуется копия, хотя, как вы упомянули, это было требованием (в комментариях).

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


Редактирование # 2:

Учитывая этот комментарий:

Ои просто усложнять вещи!список (на данный момент) имеет анонимный тип из пары запросов linq

Если вы действительно хотите использовать синтаксис стиля LINQ, я бы рекомендовал просто не вызывать ToList() в исходных запросах,Если вы оставите их в их исходной форме IEnumerable<T>, вы легко сможете выполнить мой второй вариант, описанный выше, но для исходного запроса:

var myList = query.Select(f => f.ShouldCalculate ? f.Calculate() : f).ToList();

Преимущество этого состоит в том, что список создается только один раз, ипредотвращение копирования, так как исходная последовательность не будет оценена до этой операции.

2 голосов
/ 04 сентября 2011

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

Учитывая, что вы хотите изменить список на местеLINQ не очень подходит.

Согласно предложению Рида, я бы использовал прямую петлю for.Однако, если вы хотите выполнить разные вычисления в разных точках, вы можете заключить в капсулу это:

public static void Recalculate<T>(IList<T> list,
                                  Func<T, bool> shouldCalculate,
                                  Func<T, T> calculation)
{
    for (int i = 0; i < list.Count; i++)
    {
        if (shouldCalculate(items[i]))
        {
            items[i] = calculation(items[i]);
        }
    }
}

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

И, как и Рид, я бы тоже предпочитаю делать это, создавая новую последовательность ...

0 голосов
/ 04 сентября 2011

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

Таким образом, обновление ссылочных типов не является проблемой.

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


1 Разумеется, помня, что изменяемые типы значений являются злыми .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...