1. ホーム
  2. c#

[解決済み] Linq:GroupBy、Sum、およびCount

2022-04-25 07:48:53

質問

私は製品のコレクションを持っている

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を使って商品コードでグループ化し、合計を計算するとともに、商品コードごとにレコード数をカウントしています。

今のところ、こんな感じです。

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>();

なぜか、sumは正しく行われるのに、countは常に1になってしまいます。

サンプのデータです。

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はcount = 2であるべきだ!

簡単なコンソール・アプリケーションでシミュレーションしてみましたが、次のような結果になりました。

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

Product1:は1回しか表示されないはずですが...。 上記のコードはpastebinに掲載されています。 http://pastebin.com/cNHTBSie

解決方法は?

最初の "result with sample data" がどこから来ているのか理解できませんが、コンソールアプリの問題点は 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() ここで商品名を取得するために、同じ商品コードの商品はすべて同じ商品名であると仮定しています。コメントで指摘されているように、商品コードだけでなく商品名でもグループ化することができます。

また、この際なので QuantityPrice プロパティを intdecimal 明らかにテキストではないデータに対して、なぜstringプロパティを使用するのでしょうか?