C#/VB.NET LINQのGroupByの使い方:グループ化する方法

C#やVBでもSQLで使えるGroupByを使ってグループ化できたら便利なんだけどできないのかな…?

LINQのGoupByを利用することでグループ化できます。
Select区などを駆使することで.NetでもSQLと似た感覚で利用することができます。

目次

GroupByメソッドとは

 リスト内の要素をグループ化するために「GroupBy」メソッドが提供されています。このメソッドを使うことで、同じキーを持つ要素をグループ化して、それぞれのグループを別々のグループに分割することができます。

GroupByメソッドの使い方:コレクション要素をグループ化

 LINQのGroupByメソッドを使えば、コレクションの要素をグループ化することができます。 GroupByメソッドを使うと、要素をグループ化した結果を取得することができます。

 GroupByメソッドを使うには、まず「System.Linq」名前空間をインポートする必要があります。次に、GroupByメソッドを使用するリストを定義します。このメソッドは、次のような形式で呼び出されます。

var groups = list.GroupBy(x => x.Key);

ここで、「x」はリスト内の要素を表し、「x.Key」はグループ化するキーを表します。グループ化された結果を格納する変数は「groups」としました。

以下のサンプルテーブルを使ってグループ化を行います。

TypeNamePoints
食事サカナ10
食事サカナ15
回復やくそう20
回復どくけし30
武器40
サンプルのコレクションイメージ

単一キーでのグループ化

以下の例では、アイテムのタイプによってグループ分けを行い、指定したキーごとに出力を行うサンプルです。

「GroupBy」により、「lstItem」リストの要素を「Type」フィールドの値でグループ分けしています。

 グループ分けされた結果が「query」という変数に格納されます。最後に「query」をforeach文を使って反復処理することで、グループごとに「Type」フィールドの値と「Item」オブジェクトの「Name」「Points」フィールドの値を出力しています。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace shapetest20221103
{
    class Item
    {
        public string Type;
        public string Name;
        public int Points;
    }

    public partial class Form1 : Form
    {
        public Form1()
        { InitializeComponent(); }

        private void button1_Click(object sender, EventArgs e)
        {
            List<Item> lstItem = new List<Item>() { 
                                    new Item { Points =10, Name ="サカナ", Type = "食事"},
                                    new Item { Points =15, Name ="サカナ", Type = "食事"},
                                    new Item { Points =20, Name ="やくそう", Type = "回復"},
                                    new Item { Points =30, Name ="どくけし", Type = "回復"},
                                    new Item { Points =40, Name ="剣", Type = "武器"},
                                    };

            var query = lstItem.GroupBy(x => x.Type);
            foreach (var group in query)
            {
                Debug.Print(group.Key);
                foreach (var item in group)
                {
                    Debug.Print("{0}:{1}点", item.Name, item.Points);
                }
            }
        }
    }
}
Public Class Form1

	Class Item
		Public Type As String
		Public Name As String
		Public Points As Integer
	End Class

	Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

		Dim lstItem As New List(Of Item)() From {
													New Item() With {
														.Points = 10,
														.Name = "サカナ",
														.Type = "食事"
													},
													New Item() With {
														.Points = 15,
														.Name = "サカナ",
														.Type = "食事"
													},
													New Item() With {
														.Points = 20,
														.Name = "やくそう",
														.Type = "回復"
													},
													New Item() With {
														.Points = 30,
														.Name = "どくけし",
														.Type = "回復"
													},
													New Item() With {
														.Points = 40,
														.Name = "剣",
														.Type = "武器"
													}
												}


		Dim query = lstItem.GroupBy(Function(x) x.Type)
		For Each group In query
			Debug.Print(group.Key)
			For Each item In group
				Debug.Print("{0}:{1}点", item.Name, item.Points)
			Next
		Next

	End Sub
End Class
食事
サカナ:10点
サカナ:15点
回復
やくそう:20点
どくけし:30点
武器
剣:40点

複数キーでのグループ化

複数キーでグループ化を行い場合は、GroupBy内にnew区を使って複数のキーを指定します。

 GroupByメソッドは「Type」と「Name」の2つのフィールドをグループのキーとして使用するため、「new { x.Type, x.Name }」という形で複数のキーを指定しています。

var query = lstItem.GroupBy(x => new { x.Type, x.Name});
Dim query = lstItem.GroupBy(Function(x) New With { Key x.Type, Key x.Name	})
VB.NETの場合の注意

VB.netでは匿名型にキーを指定する場合は、Keyキーワードを付与する必要があります。

例:lstItem.GroupBy(Function(x) New With {Key x.Type,Key x.Name})

以下が全体のサンプルプログラムです。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace shapetest20221103
{
    class Item
    {
        public string Type;
        public string Name;
        public int Points;
    }

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            List<Item> lstItem = new List<Item>() { 
                                    new Item { Points =10, Name ="サカナ", Type = "食事"},
                                    new Item { Points =15, Name ="サカナ", Type = "食事"},
                                    new Item { Points =20, Name ="やくそう", Type = "回復"},
                                    new Item { Points =30, Name ="どくけし", Type = "回復"},
                                    new Item { Points =40, Name ="剣", Type = "武器"},
                                    };

            //new区で複数のキーを指定する
            var query = lstItem.GroupBy(x => new { x.Type,
                                                   x.Name});

            foreach (var group in query)
            {
                Debug.Print(group.Key.Name);
                Debug.Print(group.Key.Type);

                foreach (var item in group)
                {
                    Debug.Print("{0}:{1}点", item.Name, item.Points);
                    
                }
            }
        }
    }
}
Public Class Form1

	Class Item
		Public Type As String
		Public Name As String
		Public Points As Integer
	End Class

	Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

		Dim lstItem As New List(Of Item)() From {
													New Item() With {
														.Points = 10,
														.Name = "サカナ",
														.Type = "食事"
													},
													New Item() With {
														.Points = 15,
														.Name = "サカナ",
														.Type = "食事"
													},
													New Item() With {
														.Points = 20,
														.Name = "やくそう",
														.Type = "回復"
													},
													New Item() With {
														.Points = 30,
														.Name = "どくけし",
														.Type = "回復"
													},
													New Item() With {
														.Points = 40,
														.Name = "剣",
														.Type = "武器"
													}
												}


		'new区で複数のキーを指定する
		' VB.netでは匿名型にキーを指定する場合は、Keyキーワードを付与する必要があります。
		Dim query = lstItem.GroupBy(Function(x) New With {
														 Key x.Type,
														 Key x.Name
														})

		For Each group In query
			Debug.Print(group.Key.Name)
			Debug.Print(group.Key.Type)

			For Each item In group

				Debug.Print("{0}:{1}点", item.Name, item.Points)
			Next
		Next

	End Sub
End Class
サカナ
食事
サカナ:10点
サカナ:15点
やくそう
回復
やくそう:20点
どくけし
回復
どくけし:30点
剣
武器
剣:40点

LINQのSelect区を使ってグループごとの点数合計を取得する

 LINQのラムダ式を使用すると、「GroupBy」と「Select」を組み合わせて、分類したグループ内の数値を合計することができます。

このことを実現するには、「GroupBy」でグループ分けした後、「Select」を使ってグループ内の数値を合計するために「SUM」関数を適用することができます。

抜粋した例:

            var list = query.Select(x => new
            {
                Points = x.Sum(x => x.Points),
                Name = x.Key.Name,
                Type = x.Key.Type
            }).ToList()
		'グループごとの合計をLINQのSelect区を使って取得する
		Dim list = query.Select(Function(x) New With {
														Key .Points = x.Sum(Function(xx) xx.Points),
														Key .Name = x.Key.Name,
														Key .Type = x.Key.Type
													}).ToList()

以下が全体のサンプルプログラムです。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;

namespace shapetest20221103
{
    class Item
    {
        public string Type;
        public string Name;
        public int Points;
    }

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            List<Item> lstItem = new List<Item>() { 
                                    new Item { Points =10, Name ="サカナ", Type = "食事"},
                                    new Item { Points =15, Name ="サカナ", Type = "食事"},
                                    new Item { Points =20, Name ="やくそう", Type = "回復"},
                                    new Item { Points =30, Name ="どくけし", Type = "回復"},
                                    new Item { Points =40, Name ="剣", Type = "武器"},
                                    };

            //new区で複数のキーを指定する
            var query = lstItem.GroupBy(x => new { x.Type,
                                                   x.Name});

            //グループごとの合計をLINQのSelect区を使って取得する

            var list = query.Select(x => new
            {
                Points = x.Sum(x => x.Points),
                Name = x.Key.Name,
                Type = x.Key.Type
            }).ToList();

            foreach (var it in list)
            {
                Debug.Print("{0}:{1}点,{2}", it.Name, it.Points,it.Type);
            }
        }
    }
}
Public Class Form1

	Class Item
		Public Type As String
		Public Name As String
		Public Points As Integer
	End Class

	Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click


		Dim lstItem As New List(Of Item)() From {
													New Item() With {
														.Points = 10,
														.Name = "サカナ",
														.Type = "食事"
													},
													New Item() With {
														.Points = 15,
														.Name = "サカナ",
														.Type = "食事"
													},
													New Item() With {
														.Points = 20,
														.Name = "やくそう",
														.Type = "回復"
													},
													New Item() With {
														.Points = 30,
														.Name = "どくけし",
														.Type = "回復"
													},
													New Item() With {
														.Points = 40,
														.Name = "剣",
														.Type = "武器"
													}
												}

		'new区で複数のキーを指定する
		' VB.netでは匿名型にキーを指定する場合は、Keyキーワードを付与する必要があります。
		Dim query = lstItem.GroupBy(Function(x) New With {
														 Key x.Type,
														 Key x.Name
														})

		'グループごとの合計をLINQのSelect区を使って取得する
		Dim list = query.Select(Function(x) New With {
														Key .Points = x.Sum(Function(xx) xx.Points),
														Key .Name = x.Key.Name,
														Key .Type = x.Key.Type
													}).ToList()

		For Each it In list
			Debug.Print("{0}:{1}点,{2}", it.Name, it.Points, it.Type)
		Next

	End Sub
End Class

グループ化されているサカナが合計されて統合されています。

サカナ:25点,食事
やくそう:20点,回復
どくけし:30点,回復
剣:40点,武器

リスキリングでキャリアアップしてみませんか?

リスキリング(学び直し)は、経済産業省が推奨しており、

今だけ、最大70%のキャッシュバックを受けることができます。

リスキリング 給付金が出るスクール紹介

最大70%の給付金が出るおすすめのプログラミングスクール!

国策で予算が決められているため申し込みが多い場合は早期に終了する可能性があります!

興味のある方はすぐに確認しましょう。

GroupByでコレクションのグループ化を行うことができました。

GroupByでグループ化することによってLINQのSelectから合計のSumやカウントをとるCountなどデータベースのSQLと似た感覚で使えるようになります。慣れるととても便利なので使いこなしましょう!

Microsoft Learnの解説

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次