LINQ суммирование элементов для возврата объекта с результатами (несколько столбцов)
Я знаю, что могу сделать это с помощью foreach, но задавался вопросом, есть ли в LINQ чистый и "более сексуальный" способ.
public class item
{
public int total { get; set; }
public int net { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<item> items = new List<item>()
{
new item() { total = 123, net = 423},
new item() { total = 432, net = 54},
new item() { total = 33, net = 57654},
new item() { total = 33, net = 423},
new item() { total = 3344, net = 423},
new item() { total = 123, net = 423},
new item() { total = 123, net = 98},
new item() { total = 123, net = 867},
new item() { total = 123, net = 876},
new item() { total = 123, net = 423},
new item() { total = 123, net = 543},
new item() { total = 543, net = 345},
};
item i = new item();
foreach (var item in items)
{
i.net += item.net;
i.total += item.total;
}
}
}
Что я хотел бы сделать, так как данный список объектов суммирует каждый из столбцов/полей и возвращает один единственный объект с суммой каждого значения.
Я пробовал:
var result = (from e in items
select new
{
NET_GRAND = e.net,
TOTAL_GRAND = e.total
}).ToList();
И варианты ниже, но без везения:
var result = (from t in items
group t by new {t.net, t.total}
into grp
select new
{
NET_GRAND = grp.Sum(t => t.net),
TOTAL_GRAND = grp.Sum(t => t.total)
}).GroupBy(x => new { x.NET_GRAND, x.TOTAL_GRAND }).ToList();
ИЗМЕНИТЬ
должен был указать, что здесь важна эффективность, а также сексуальность.
Ответы
Ответ 1
Если вам не нужно дважды повторять список,
var i = new item
{
net = items.Sum(it => it.net),
total = items.Sum(it => it.total)
};
Если вы позаботились о повторении списка дважды (как вы могли бы, если бы вы делали это для IEnumerable
неизвестного происхождения),
var i = items.Aggregate(new item(),
(accumulator, it) =>
new item
{
net = accumulator.net + it.net,
total = accumulator.total + it.total
}
);
Ответ 2
Похоже, вы действительно хотите:
var result = new {
NetGrand = items.Sum(t => t.net),
TotalGrand = items.Sum(t => t.total)
};
С другой стороны, я бы, вероятно, просто разделил их на две разные локальные переменные:
var netGrand = items.Sum(t => t.net);
var totalGrand = items.Sum(t => t.total);
Конечно, это повторяется по списку дважды, но в большинстве случаев я ожидаю, что это не будет заметно.
Ответ 3
item totals = new item
{
net = items.Sum(i => i.net),
total = items.Sum(i => i.total)
};
Но имейте в виду, что этот запрос будет перечислять список два раза, поэтому для большого списка это будет не так эффективно, как старый хороший одиночный цикл foreach
.
Ответ 4
var item = new item();
item.net = items .Sum(x=>x.net);
item.total = items.Sum(x=>x.total);
Ответ 5
Используйте цикл foreach. Вы заявляете, что вас беспокоит эффективность, и даже если вы не были там, нет причин писать его с помощью Linq только для использования Linq.
Одна из вещей, которые мы обнаруживаем, когда мы получаем больше опыта работы с программами, состоит в том, что только потому, что что-то делается "по-старому", не делает это плохо. И переход на новый метод wiz-bang не делает его лучше. Фактически, если у вас есть код, работающий по-старому, "обновление" является причиной для инъекций дефектов, во многих случаях нет преимуществ.
В лучшем случае этот метод Linq займет 2X для вычисления.
var i = new item
{
net = items.Sum(it => it.net),
total = items.Sum(it => it.total)
};
Не уверен в сводном методе, но, очевидно, это займет больше времени.