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」としました。
以下のサンプルテーブルを使ってグループ化を行います。
Type | Name | Points |
---|---|---|
食事 | サカナ | 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では匿名型にキーを指定する場合は、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と似た感覚で使えるようになります。慣れるととても便利なので使いこなしましょう!