今回は、GroupJoin拡張メソッドについてです。
GroupJoin拡張メソッドは、クエリ式での「join xx in xx on xx equals xx into xx」に対応する拡張メソッドです。
LINQでのグループ結合については、以前の記事で記述していますので、そちらを参照下さればと思います。
- Linq入門記-10 (クエリキーワード, クエリ構文, 結合, join, グループ化結合, group join, equals, into)
GroupJoin拡張メソッドの書式は以下の通りです。
public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>( this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector ) public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>( this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey> comparer )
一つ目の書式が一番よく利用される形のものですね。
2つめの書式は、一つ目の分にIEqualityComparer
キーの同値性を独自の方法で決定する際に利用します。
引数が多いですが、慣れるとそんなに難しくありません。
クエリ式で
from team in teams join person in people on team equals person.Team into personCollection select new { Team = team, Persons = personCollection }
という記述は、
teams.GroupJoin(people, team => team, person => person.Team, (team, personCollection) => new { Team = team, Persons = personCollection })
となります。
Join拡張メソッドとほとんど同じなのですが、こちらは階層構造を構築してくれます。
つまり、TOuter(上記の例でいうとTeamオブジェクト)単位に、結合されたTInnerのシーケンス(上記の例でいうとPersonオブジェクト)が
がくっつく形になります。
[Join拡張メソッドの場合]
Team | Person |
t1 | p1 |
t1 | p2 |
t2 | p3 |
[GroupJoin拡張メソッドの場合]
- t1
- p1
- p2
- t2
- p3
のイメージです。
以下、サンプルです。
#region LinqSamples-27 public class LinqSamples27 : IExecutable { class Person { public string Name { get; set; } public Team Team { get; set; } } class Team { public string Name { get; set; } } public void Execute() { var t1 = new Team { Name = "Team 1" }; var t2 = new Team { Name = "Team 2" }; var p1 = new Person { Name = "gsf_zero1", Team = t1 }; var p2 = new Person { Name = "gsf_zero2", Team = t2 }; var p3 = new Person { Name = "gsf_zero3", Team = t1 }; var teams = new List<Team> { t1, t2 }; var people = new List<Person> { p1, p2, p3 }; // // グループ結合する. // // Join拡張メソッドと書式的にはほとんど同じであるが、以下の点が異なる。 // ・resultSelectorの書式が、(TOuter, IEnumerable<TInner>)となっている。 // これにより、結果をJOINした結果をグルーピングした状態で保持することが出来る。(階層構造を構築出来る。) // // 以下のクエリ式と同じ事となる。 // from team in teams // join person in people on team equals person.Team into personCollection // select new { Team = team, Persons = personCollection } // var query = teams.GroupJoin // TOuter ( people, // TInner team => team, // TOuterのキー person => person.Team, // TInnerのキー (team, personCollection) => // 結果 (TOuter, IEnumerable<TInner>) new { Team = team, Persons = personCollection } ); foreach (var item in query2) { Console.WriteLine("TEAM = {0}", item.Team.Name); foreach (var p in item.Persons) { Console.WriteLine("\tPERSON = {0}", p.Name); } } } } #endregion
実行結果は以下の通りです。
TEAM = Team 1 PERSON = gsf_zero1 PERSON = gsf_zero3 TEAM = Team 2 PERSON = gsf_zero2
================================
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ