Linq: GroupBy, сумма и количество

У меня есть коллекция продуктов

public class Product {

   public Product() { }

   public string ProductCode {get; set;}
   public decimal Price {get; set; }
   public string Name {get; set;}
}

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

public class ResultLine{

   public ResultLine() { }

   public string ProductName {get; set;}
   public string Price {get; set; }
   public string Quantity {get; set;}
}

Поэтому я использую GroupBy для группировки по ProductCode, затем вычисляю сумму, а также подсчитываю количество записей для каждого кода продукта.

Это то, что я имею до сих пор:

List<Product> Lines = LoadProducts();    
List<ResultLine> result = Lines
                .GroupBy(l => l.ProductCode)
                .SelectMany(cl => cl.Select(
                    csLine => new ResultLine
                    {
                        ProductName =csLine.Name,
                        Quantity = cl.Count().ToString(),
                        Price = cl.Sum(c => c.Price).ToString(),
                    })).ToList<ResultLine>();

По какой-то причине сумма сделана правильно, но счет всегда равен 1.

Данные Sampe:

List<CartLine> Lines = new List<CartLine>();
            Lines.Add(new CartLine() { ProductCode = "p1", Price = 6.5M, Name = "Product1" });
            Lines.Add(new CartLine() { ProductCode = "p1", Price = 6.5M, Name = "Product1" });
            Lines.Add(new CartLine() { ProductCode = "p2", Price = 12M, Name = "Product2" });

Результат с примерами данных:

Product1: count 1   - Price:13 (2x6.5)
Product2: count 1   - Price:12 (1x12)

Продукт 1 должен иметь число = 2!

Я пытался смоделировать это в простом консольном приложении, но там я получил следующий результат:

Product1: count 2   - Price:13 (2x6.5)
Product1: count 2   - Price:13 (2x6.5)
Product2: count 1   - Price:12 (1x12)

Product1: должен быть указан только один раз ... Код для вышеупомянутого можно найти на pastebin: http://pastebin.com/cNHTBSie

94 голоса | спросил ThdK 13 Maypm13 2013, 16:57:33

2 ответа


0

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

Я думаю, что вы просто хотите:

List<ResultLine> result = Lines
    .GroupBy(l => l.ProductCode)
    .Select(cl => new ResultLine
            {
                ProductName = cl.First().Name,
                Quantity = cl.Count().ToString(),
                Price = cl.Sum(c => c.Price).ToString(),
            }).ToList();

Использование First() здесь для получения названия продукта предполагает, что каждый продукт с одинаковым кодом продукта имеет одинаковое название продукта. Как отмечено в комментариях, вы можете группировать по названию продукта, а также по коду продукта, что даст одинаковые результаты, если имя всегда одинаково для любого кода, но, очевидно, генерирует лучший SQL в EF.

Я также предлагаю вам изменить Quantity и Price свойства должны быть int и decimal типы соответственно - зачем использовать строковое свойство для данных, которые явно не текстовые?

ответил Jon Skeet 13 Maypm13 2013, 17:07:08
0

Следующий запрос работает. Он использует каждую группу для выбора вместо SelectMany. SelectMany работает с каждым элементом из каждой коллекции. Например, в вашем запросе у вас есть результат 2 коллекции. SelectMany получает все результаты (всего 3) вместо каждой коллекции. Следующий код работает с каждым IGrouping в выбранной части, чтобы ваши агрегатные операции работали правильно.

var results = from line in Lines
              group line by line.ProductCode into g
              select new ResultLine {
                ProductName = g.First().Name,
                Price = g.Sum(_ => _.Price).ToString(),
                Quantity = g.Count().ToString(),
              };
ответил Charles Lambert 13 Maypm13 2013, 17:31:44

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132