【C#】GroupBy()を使用したリストのグループ分け

LINQのGroupByメソッドを使用することで、リストを特定のプロパティの値でグループ分けすることができます。

やりたいこと

以下のプロパティを持つProductクラスがあります。

  • ID
  • 名前(Name)
  • カテゴリー(Category)
  • 価格(Price)
  • 個数(Quantity)

このクラス型の要素を持つproductsに対して、商品のカテゴリー別にグループ分けして、各カテゴリーごとに処理を行いたいです。

今回は以下のように、商品Productの情報をカテゴリーCategoryごとにまとめて表示したいと思います。

【Category : Fruit 】
Id: 1, Name: Apple, Category: Fruit, Price: 120, Quantity: 50
Id: 2, Name: Banana, Category: Fruit, Price: 80, Quantity: 30
Id: 9, Name: Grapes, Category: Fruit, Price: 200, Quantity: 15
Id: 11, Name: Orange, Category: Fruit, Price: 150, Quantity: 35
Id: 16, Name: Strawberry, Category: Fruit, Price: 300, Quantity: 20
Id: 20, Name: Peach, Category: Fruit, Price: 200, Quantity: 30
Id: 22, Name: Mango, Category: Fruit, Price: 250, Quantity: 15
Id: 26, Name: Pineapple, Category: Fruit, Price: 300, Quantity: 10
Id: 30, Name: Melon, Category: Fruit, Price: 180, Quantity: 20

【Category : Vegetable 】
Id: 3, Name: Carrot, Category: Vegetable, Price: 100, Quantity: 20
Id: 4, Name: Tomato, Category: Vegetable, Price: 120, Quantity: 40
Id: 10, Name: Potato, Category: Vegetable, Price: 50, Quantity: 100
Id: 15, Name: Cucumber, Category: Vegetable, Price: 150, Quantity: 25
Id: 17, Name: Lettuce, Category: Vegetable, Price: 90, Quantity: 30
Id: 21, Name: Radish, Category: Vegetable, Price: 70, Quantity: 20
Id: 23, Name: Sweet Corn, Category: Vegetable, Price: 110, Quantity: 40
Id: 27, Name: Spinach, Category: Vegetable, Price: 80, Quantity: 35

【Category : Dairy 】
Id: 5, Name: Milk, Category: Dairy, Price: 180, Quantity: 20
Id: 6, Name: Cheese, Category: Dairy, Price: 300, Quantity: 10
Id: 12, Name: Yogurt, Category: Dairy, Price: 150, Quantity: 20
Id: 13, Name: Ice Cream, Category: Dairy, Price: 300, Quantity: 10
Id: 18, Name: Butter, Category: Dairy, Price: 250, Quantity: 5
Id: 24, Name: Cream, Category: Dairy, Price: 220, Quantity: 10
Id: 28, Name: Whipped Cream, Category: Dairy, Price: 240, Quantity: 10

【Category : Snacks 】
Id: 7, Name: Chips, Category: Snacks, Price: 100, Quantity: 40
Id: 8, Name: Chocolate, Category: Snacks, Price: 250, Quantity: 25
Id: 14, Name: Breadsticks, Category: Snacks, Price: 120, Quantity: 50
Id: 19, Name: Crackers, Category: Snacks, Price: 100, Quantity: 40
Id: 25, Name: Biscuits, Category: Snacks, Price: 130, Quantity: 25
Id: 29, Name: Popcorn, Category: Snacks, Price: 90, Quantity: 50

GroupByを使ってグループ分け

GroupBy()を使うことで、引数で指定したプロパティでリストをグループ分けすることができます。

// カテゴリーCategoryごとにグループ化
var productsGroupedByCategory = products.GroupBy(x => x.Category);

戻り値は「IEnumerable<IGrouping<Key, Element>>」と少し複雑ですが、イメージとしては「各グループのリストを要素として持つリスト」が返ってくる感じになります。

コードで見てみるとわかりやすいと思います。

// カテゴリーごとに商品を表示
foreach (var group in productsGroupedByCategory)
{
    // 各グループごとの処理
    Console.WriteLine($"【Category : {group.First().Category} 】");

    foreach(var product in group)
    {
        // 1商品の情報を表示
        Console.WriteLine($"Id: {product.Id}, Name: {product.Name}, Category: {product.Category}, Price: {product.Price}, Quantity: {product.Quantity}");
    }

    // ただの改行
    Console.WriteLine();
}

まず、外側のforeachです。
GroupBy()の戻り値productsGroupedByCategoryをforeachを使ってグループごとに分割します。これによりforeachの内部では特定のグループのリストgroupが扱えるようになります。

つぎに、内側のforeachです。
特定のグループのリストgroupをforeachを使って分割します。これにより1要素(今回の例では1商品)が扱えるようにします。

コード全体

〇 メインプログラム(エントリポイント)

public class Program
{
    static void Main(string[] args)
    {
        // 商品データの作成
        var products = new List<Product>
        {
            new Product { Id = 1, Name = "Apple", Category = ProductCategory.Fruit, Price = 120, Quantity = 50 },
            new Product { Id = 2, Name = "Banana", Category = ProductCategory.Fruit, Price = 80, Quantity = 30 },
            new Product { Id = 3, Name = "Carrot", Category = ProductCategory.Vegetable, Price = 100, Quantity = 20 },
            new Product { Id = 4, Name = "Tomato", Category = ProductCategory.Vegetable, Price = 120, Quantity = 40 },
            new Product { Id = 5, Name = "Milk", Category = ProductCategory.Dairy, Price = 180, Quantity = 20 },
            new Product { Id = 6, Name = "Cheese", Category = ProductCategory.Dairy, Price = 300, Quantity = 10 },
            new Product { Id = 7, Name = "Chips", Category = ProductCategory.Snacks, Price = 100, Quantity = 40 },
            new Product { Id = 8, Name = "Chocolate", Category = ProductCategory.Snacks, Price = 250, Quantity = 25 },
            new Product { Id = 9, Name = "Grapes", Category = ProductCategory.Fruit, Price = 200, Quantity = 15 },
            new Product { Id = 10, Name = "Potato", Category = ProductCategory.Vegetable, Price = 50, Quantity = 100 },
            new Product { Id = 11, Name = "Orange", Category = ProductCategory.Fruit, Price = 150, Quantity = 35 },
            new Product { Id = 12, Name = "Yogurt", Category = ProductCategory.Dairy, Price = 150, Quantity = 20 },
            new Product { Id = 13, Name = "Ice Cream", Category = ProductCategory.Dairy, Price = 300, Quantity = 10 },
            new Product { Id = 14, Name = "Breadsticks", Category = ProductCategory.Snacks, Price = 120, Quantity = 50 },
            new Product { Id = 15, Name = "Cucumber", Category = ProductCategory.Vegetable, Price = 150, Quantity = 25 },
            new Product { Id = 16, Name = "Strawberry", Category = ProductCategory.Fruit, Price = 300, Quantity = 20 },
            new Product { Id = 17, Name = "Lettuce", Category = ProductCategory.Vegetable, Price = 90, Quantity = 30 },
            new Product { Id = 18, Name = "Butter", Category = ProductCategory.Dairy, Price = 250, Quantity = 5 },
            new Product { Id = 19, Name = "Crackers", Category = ProductCategory.Snacks, Price = 100, Quantity = 40 },
            new Product { Id = 20, Name = "Peach", Category = ProductCategory.Fruit, Price = 200, Quantity = 30 },
            new Product { Id = 21, Name = "Radish", Category = ProductCategory.Vegetable, Price = 70, Quantity = 20 },
            new Product { Id = 22, Name = "Mango", Category = ProductCategory.Fruit, Price = 250, Quantity = 15 },
            new Product { Id = 23, Name = "Sweet Corn", Category = ProductCategory.Vegetable, Price = 110, Quantity = 40 },
            new Product { Id = 24, Name = "Cream", Category = ProductCategory.Dairy, Price = 220, Quantity = 10 },
            new Product { Id = 25, Name = "Biscuits", Category = ProductCategory.Snacks, Price = 130, Quantity = 25 },
            new Product { Id = 26, Name = "Pineapple", Category = ProductCategory.Fruit, Price = 300, Quantity = 10 },
            new Product { Id = 27, Name = "Spinach", Category = ProductCategory.Vegetable, Price = 80, Quantity = 35 },
            new Product { Id = 28, Name = "Whipped Cream", Category = ProductCategory.Dairy, Price = 240, Quantity = 10 },
            new Product { Id = 29, Name = "Popcorn", Category = ProductCategory.Snacks, Price = 90, Quantity = 50 },
            new Product { Id = 30, Name = "Melon", Category = ProductCategory.Fruit, Price = 180, Quantity = 20 }
        };

        // カテゴリーごとにグループ化
        var productsGroupedByCategory = products.GroupBy(x => x.Category);

        // カテゴリーごとに商品を表示
        foreach (var group in productsGroupedByCategory)
        {
            // 各グループごとの処理
            Console.WriteLine($"【Category : {group.First().Category} 】");

            foreach(var product in group)
            {
                // 1商品の情報を表示
                Console.WriteLine($"Id: {product.Id}, Name: {product.Name}, Category: {product.Category}, Price: {product.Price}, Quantity: {product.Quantity}");
            }

            // ただの改行
            Console.WriteLine();
        }
    }
}

〇 商品クラス

/// <summary>
/// 商品を表します
/// </summary>
public class Product
{
    /// <summary>
    /// ID
    /// </summary>
    public int Id { get; set; }

    /// <summary>
    /// 名前
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// カテゴリー
    /// </summary>
    public ProductCategory Category { get; set; }

    /// <summary>
    /// 単価
    /// </summary>
    public int Price { get; set; }

    /// <summary>
    /// 在庫数
    /// </summary>
    public int Quantity { get; set; }
}

〇 カテゴリ列挙

/// <summary>
/// カテゴリーを表します
/// </summary>
public enum ProductCategory
{
    /// <summary>
    /// 果物
    /// </summary>
    Fruit,
    /// <summary>
    /// 野菜
    /// </summary>
    Vegetable,
    /// <summary>
    /// 乳製品
    /// </summary>
    Dairy,
    /// <summary>
    /// スナック
    /// </summary>
    Snacks
}

〇 出力

【Category : Fruit 】
Id: 1, Name: Apple, Category: Fruit, Price: 120, Quantity: 50
Id: 2, Name: Banana, Category: Fruit, Price: 80, Quantity: 30
Id: 9, Name: Grapes, Category: Fruit, Price: 200, Quantity: 15
Id: 11, Name: Orange, Category: Fruit, Price: 150, Quantity: 35
Id: 16, Name: Strawberry, Category: Fruit, Price: 300, Quantity: 20
Id: 20, Name: Peach, Category: Fruit, Price: 200, Quantity: 30
Id: 22, Name: Mango, Category: Fruit, Price: 250, Quantity: 15
Id: 26, Name: Pineapple, Category: Fruit, Price: 300, Quantity: 10
Id: 30, Name: Melon, Category: Fruit, Price: 180, Quantity: 20

【Category : Vegetable 】
Id: 3, Name: Carrot, Category: Vegetable, Price: 100, Quantity: 20
Id: 4, Name: Tomato, Category: Vegetable, Price: 120, Quantity: 40
Id: 10, Name: Potato, Category: Vegetable, Price: 50, Quantity: 100
Id: 15, Name: Cucumber, Category: Vegetable, Price: 150, Quantity: 25
Id: 17, Name: Lettuce, Category: Vegetable, Price: 90, Quantity: 30
Id: 21, Name: Radish, Category: Vegetable, Price: 70, Quantity: 20
Id: 23, Name: Sweet Corn, Category: Vegetable, Price: 110, Quantity: 40
Id: 27, Name: Spinach, Category: Vegetable, Price: 80, Quantity: 35

【Category : Dairy 】
Id: 5, Name: Milk, Category: Dairy, Price: 180, Quantity: 20
Id: 6, Name: Cheese, Category: Dairy, Price: 300, Quantity: 10
Id: 12, Name: Yogurt, Category: Dairy, Price: 150, Quantity: 20
Id: 13, Name: Ice Cream, Category: Dairy, Price: 300, Quantity: 10
Id: 18, Name: Butter, Category: Dairy, Price: 250, Quantity: 5
Id: 24, Name: Cream, Category: Dairy, Price: 220, Quantity: 10
Id: 28, Name: Whipped Cream, Category: Dairy, Price: 240, Quantity: 10

【Category : Snacks 】
Id: 7, Name: Chips, Category: Snacks, Price: 100, Quantity: 40
Id: 8, Name: Chocolate, Category: Snacks, Price: 250, Quantity: 25
Id: 14, Name: Breadsticks, Category: Snacks, Price: 120, Quantity: 50
Id: 19, Name: Crackers, Category: Snacks, Price: 100, Quantity: 40
Id: 25, Name: Biscuits, Category: Snacks, Price: 130, Quantity: 25
Id: 29, Name: Popcorn, Category: Snacks, Price: 90, Quantity: 50

コメント