Операторы C # Linq или foreach () для суммирования подмножеств?
Вопрос
Какое из этих решений предпочтительнее? Р>
Для списка:
List<ExampleInfo> exampleList = new List<ExampleInfo>();
public class ExampleInfo
{
internal ExampleInfo()
{ }
/* Business Properties */
public int Id { get; set; }
public string Type { get; set; }
public decimal Total { get; set; }
}
Я хочу получить промежуточные итоги на основе значения «Итого». Р>
Вариант 1:
var subtotal1 = exampleList.Where(x => x.Type == "Subtype1").Sum(x => x.Total);
var subtotal2 = exampleList.Where(x => x.Type == "Subtype2").Sum(x => x.Total);
Вариант 2:
decimal subtotal1 = 0m;
decimal subtotal2 = 0m;
foreach (ExampleInfo example in exampleList)
{
switch (example.Type)
{
case "Subtype1":
subtotal1 += example.Total;
break;
case "Subtype2":
subtotal2 += example.Total;
break;
default:
break;
}
}
Список будет < 10 пунктов в большинстве случаев. Р>
Редактировать. Крис поднял очень хороший вопрос, который я не упомянул. Программа уже использует .NET Framework 3.5 с пакетом обновления 1 (SP1), поэтому совместимость здесь не является важным фактором.
Решение
Оба эти примера имеют дублированный код, и оба не готовы к изменению Type
- что, если у него три значения? Что если бы у него было 30?
Вы можете использовать linq для группировки по нему и получить итоговое значение:
var totals = from p in exampleList
group p by p.Type into g
select new { Type = g.Key, Total = g.Sum(p => p.Total ) };
Итак, totals
- это коллекция объектов со свойствами Total
и <=>
Другие советы
Независимо от размера списка, если вы ориентируетесь на .NET 3.5, я бы использовал LINQ, если бы только для удобства чтения.
Я большой поклонник написания того, что вы имеете в виду, а не того, как это делается, и LINQ делает это очень легко в таких случаях.
Возможно, вы даже можете объединить вычисления в один оператор LINQ, сгруппированный по типу. Таким образом, у вас не будет двух циклов для LINQ, а будет только один, как во втором примере:
var subtotals = from x in exampleList
group x by x.Type into g
select new { Type = x.Key, SubTotal = g.Sum(x => x.Total) };
(Не совсем уверен, работает ли код как есть, это просто быстрая адаптация одного из 101 пример LINQ . Синтаксис должен быть в порядке.)
Вариант 3
var groupings = exampleList
.GroupBy(x => x.Type, x => x.Total)
.Select(x => new { Type = x.Key, SubTotal = x.Sum() } );
У вас будет список классов примерно так:
class <Anonymous>
{
public string Type { get; }
public decimal SubTotal { get; }
}
Перечислите и присвойте соответствующее значение, хотя оно может быть излишним для такого небольшого набора.
Я не думаю, что для таких маленьких списков будет большая разница в производительности.
Вариант 1 повторяет список дважды, тогда как вариант 2 повторяет список только один раз. Это может быть важнее для больших списков, чем для маленьких.
Вариант 1 более читабелен, но я обязательно сделаю комментарий, чтобы он дважды просматривал список. Р>
Очевидным преимуществом варианта 2 является то, что код работает в .NET Framework 2.0. Использование LINQ означает, что вашему приложению требуется .NET Framework 3.5.
Для option1, внутренне цикл foreach будет выполняться дважды средой выполнения C #. Следовательно, тип обработки будет больше. Но для & Lt; 10 элементов это вряд ли имеет значение, и вариант 1 кажется более читабельным. Я бы выбрал вариант 1 для & Lt; 10 предметов.