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