【C#】LINQのGroupByメソッドの使い方

LINQメソッドのGroupByの使い方を簡単にまとめます。
GroupByメソッドを使うことで、キーごとにグループ化した結果を取得できます。それをforeachでループさせて使うことで、コードを簡潔に書くことが可能です。

【検証環境】.NET Framework 4.7.2

※下記のクラスを例に使います。

class Studnet
{
    //学籍番号
    public int Num { get; set; }
    //名前
    public string Name { get; set; }
    //性別(0:男性 1:女性)
    public string Sex { get; set; }
    //お小遣い
    public int Allow { get; set; }
    //クラブ
    public string Club { get; set; }

    public static List<Studnet> GetStudents()
    {
        return new List<Studnet>()
        {
            new Studnet()
            {
                Num = 101, Name = "浅田真央", Sex = "1", Allow = 10000, Club = "スケート",
            },
            new Studnet()
            {
                Num = 102, Name = "石川佳純", Sex = "1", Allow = 12000, Club = "卓球",
            },
            new Studnet()
            {
                Num = 111, Name = "イチロー", Sex = "0", Allow = 20000, Club = "野球",
            },
            new Studnet()
            {
                Num = 112, Name = "大坂なおみ", Sex = "1", Allow = 25000, Club = "テニス",
            },
            new Studnet()
            {
                Num = 113, Name = "香川真司" , Sex = "0", Allow = 30000, Club = "サッカー",
            },
            new Studnet()
            {
                Num = 121, Name = "ドログバ", Sex = "0", Allow = 35000, Club = "サッカー",
            },
            new Studnet()
            {
                Num = 122, Name = "錦織圭", Sex = "0", Allow = 40000, Club = "テニス",
            },
            new Studnet()
            {
                Num = 123, Name = "羽生結弦", Sex = "0", Allow = 45000, Club = "スケート",
            },
            new Studnet()
            {
                Num = 124, Name = "本田圭佑", Sex = "0", Allow = 50000, Club = "サッカー",
            },
        };
    }
    public static string GetSexString(string sex)
    {
        switch (sex)
        {
            case "0":
                return "男性";
            case "1":
                return "女性";
            default:
                return "";
        }
    }
}

単一のキーでグループ化

var students = Studnet.GetStudents();
//性別でグループ化
var groups = students.GroupBy(s => s.Sex).OrderBy(s => s.Key);
foreach (var group in groups)
{
    Console.WriteLine($"【{Studnet.GetSexString(group.Key)}】 {group.Count()}人");
    foreach (var part in group)
    {
        Console.WriteLine(part.Name);
    }
    Console.WriteLine();
}
Console.ReadLine();

//【男性】 6人
//イチロー
//香川真司
//ドログバ
//錦織圭
//羽生結弦
//本田圭佑
//
//【女性】 3人
//浅田真央
//石川佳純
//大坂なおみ
var students = Studnet.GetStudents();
//クラブでグループ化
var groups = students.GroupBy(s => s.Club).OrderBy(s => s.Key);
foreach (var group in groups)
{
    Console.WriteLine($"【{group.Key}部】{group.Count()}人");
    foreach (var part in group)
    {
        Console.WriteLine(part.Name);
    }
    Console.WriteLine();
}
Console.ReadLine();

//【サッカー部】3人
//香川真司
//ドログバ
//本田圭佑
//
//【スケート部】2人
//浅田真央
//羽生結弦
//
//【テニス部】2人
//大坂なおみ
//錦織圭
//
//【卓球部】1人
//石川佳純
//
//【野球部】1人
//イチロー

複数のキーでグループ化

var students = Studnet.GetStudents();
//クラブと性別でグループ化
var groups = students.GroupBy(s => new
{
    s.Club,
    s.Sex,
}).OrderBy(s => s.Key.Sex);
foreach (var group in groups)
{
    Console.Write($"【{group.Key.Club}部】");
    Console.WriteLine($" 【{ Studnet.GetSexString(group.Key.Sex)}】 {group.Count()}人");
    foreach (var part in group)
    {
        Console.WriteLine(part.Name);
    }
    Console.WriteLine();
}
Console.ReadLine();

//【野球部】 【男性】 1人
//イチロー
//
//【サッカー部】 【男性】 3人
//香川真司
//ドログバ
//本田圭佑
//
//【テニス部】 【男性】 1人
//錦織圭
//
//【スケート部】 【男性】 1人
//羽生結弦
//
//【スケート部】 【女性】 1人
//浅田真央
//
//【卓球部】 【女性】 1人
//石川佳純
//
//【テニス部】 【女性】 1人
//大坂なおみ

キーの加工

現状、学籍番号でグループ化をすると、下記のようになります。
学籍番号は一意の値なので、当然ですね。

var students = Studnet.GetStudents();
//学籍番号でグループ化
var groups = students.GroupBy(s => s.Num);
foreach (var group in groups)
{
    Console.WriteLine($"【学籍番号】{group.Key}  {group.Count()}人");
    foreach (var part in group)
    {
        Console.WriteLine(part.Name);
    }
    Console.WriteLine();
}
Console.ReadLine();

//【学籍番号】101  1人
//浅田真央
//
//【学籍番号】102  1人
//石川佳純
//
//【学籍番号】111  1人
//イチロー
//
//【学籍番号】112  1人
//大坂なおみ
//
//【学籍番号】113  1人
//香川真司
//
//【学籍番号】121  1人
//ドログバ
//
//【学籍番号】122  1人
//錦織圭
//
//【学籍番号】123  1人
//羽生結弦
//
//【学籍番号】124  1人
//本田圭佑

では、学籍番号の頭2桁でグループ化をしたい場合はどうでしょうか。
下記のようにキーの指定時に、キーを加工することで実現可能です。

var students = Studnet.GetStudents();
//学籍番号の頭2桁でグループ化
var groups = students.GroupBy(s => (s.Num / 10) * 10);
//
foreach (var group in groups)
{
    Console.WriteLine($"【学籍番号】{group.Key}番台  {group.Count()}人");
    foreach (var part in group)
    {
        Console.WriteLine($"{part.Num}:{part.Name}");
    }
    Console.WriteLine();
}
Console.ReadLine();

//【学籍番号】100番台  2人
//101:浅田真央
//102:石川佳純
//
//【学籍番号】110番台  3人
//111:イチロー
//112:大坂なおみ
//113:香川真司
//
//【学籍番号】120番台  4人
//121:ドログバ
//122:錦織圭
//123:羽生結弦
//124:本田圭佑

複数キー指定の場合は、キーの指定箇所の書き方が若干異なります。

var students = Studnet.GetStudents();
//学籍番号の頭2桁と性別でグループ化
var groups = students.GroupBy(s => new
{
    Number = (s.Num / 10) * 10,
    //メソッドでもいけます。
    //Number = Floor(s.Number),
    s.Sex,
});
foreach (var group in groups)
{
    Console.WriteLine($"【学籍番号】{group.Key.Number}番台 【{( Studnet.GetSexString(group.Key.Sex))} 】 {group.Count()}人");
    foreach (var part in group)
    {
        Console.WriteLine($"{part.Num}:{part.Name}");
    }
    Console.WriteLine();
}
Console.ReadLine();

int Floor(int value)
{
    return value / 10 * 10;
}

//【学籍番号】100番台 【女性】  2人
//101:浅田真央
//102:石川佳純

//【学籍番号】110番台 【男性】  2人
//111:イチロー
//113:香川真司

//【学籍番号】110番台 【女性】  1人
//112:大坂なおみ

//【学籍番号】120番台 【男性】  4人
//121:ドログバ
//122:錦織圭
//123:羽生結弦
//124:本田圭佑         

グループ化した結果を射影(GroupBy + Select)

var students = Studnet.GetStudents();
//性別でグループ化して任意の項目をSelect
var list = students.GroupBy(s => s.Sex)
                     .Select(group => new
                     {
                         //性別
                         sex = group.Key,
                         //人数
                         count = group.Count(),
                         //お小遣いの合計
                         sumAllowance = group.Sum(s => s.Allow),
                         //お小遣いの平均
                         averageAllowance = group.Average(s => s.Allow),
                     });
foreach (var item in list)
{
    Console.WriteLine($"性別:{Studnet.GetSexString(item.sex)} 人数:{item.count}人 お小遣い合計:{item.sumAllowance} お小遣い平均:{item.averageAllowance.ToString("0")}");
}
Console.ReadLine();
////性別:女性 人数:3人 お小遣い合計:47000 お小遣い平均:15667
////性別:男性 人数:6人 お小遣い合計:220000 お小遣い平均:36667

Leave a Reply

Your email address will not be published. Required fields are marked *