C#

【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

エンジニアの転職ならこれ!

【第二新卒向け】マイナビジョブ20's

マイナビジョブ20'sは、20代・第二新卒・既卒向けの転職エージェントです。

▼こんな方におすすめ
・はじめて転職しようと思っている
・転職できるだけのスキルが自分にあるか不安
・手厚いサポートを受けたい

【フリーランス向け】安心保障と豊富な案件紹介 Midworks

Midworksは豊富な案件と「フリーランス」と「正社員」の良いとこ取りをした働き方を実現する手厚い保障が特徴です。

▼こんな方におすすめ
・現在正社員でフリーランスになろうか悩んでいる
・フリーランスとして働いているが、先行きが不安がある  (安定的な案件確保や保障など)
・自分の市場価値を知りたい、見合った案件で参画したい
・今後のキャリアビジョンを踏まえて案件を選びたい

【未経験向け】自宅で現役エンジニアから学べる TechAcademy

テックアカデミーは、現役エンジニアから学べるオンラインに特化したプログラミングスクールです。
講師は全員、通過率10%の選考に合格した現役エンジニア。
確かなスキルをもとに受講生をマンツーマンサポートします。


▼こんな方におすすめ
・自宅にいながらオンライン完結で勉強できる
・受講生に1人ずつ現役エンジニアのパーソナルメンターが専属でつく
・チャットで質問すればすぐに回答が返ってくる
・オリジナルサービスやオリジナルアプリなどの開発までサポート