回答:
次の2つのリストがあるとします。
Id Value
1 A
2 B
3 C
Id ChildValue
1 a1
1 a2
1 a3
2 b1
2 b2
フィールドにJoin
2つのリストがある場合Id
、結果は次のようになります。
Value ChildValue
A a1
A a2
A a3
B b1
B b2
フィールドにGroupJoin
2つのリストがある場合Id
、結果は次のようになります。
Value ChildValues
A [a1, a2, a3]
B [b1, b2]
C []
したがってJoin
、親と子の値のフラットな(表形式の)結果が生成されます。
GroupJoin
最初のリストのエントリのリストを作成します。各リストには、2番目のリストの結合されたエントリのグループがあります。
なぜだというJoin
のと等価であるINNER JOIN
SQLでは:のためのエントリがありませんC
。while GroupJoin
はOUTER JOIN
:C
と同等ですが、結果セットには含まれますが、関連するエントリの空のリストが含まれます(SQL結果セットには行がありますC - null
)。
したがって、2つのリストIEnumerable<Parent>
をIEnumerable<Child>
それぞれとします。(Linq to Entitiesの場合:)IQueryable<T>
。
Join
構文は
from p in Parent
join c in Child on p.Id equals c.Id
select new { p.Value, c.ChildValue }
帰国IEnumerable<X>
ここで、Xは、2つのプロパティを持つ匿名型である、Value
とChildValue
。このクエリ構文では、Join
内部でメソッドを使用します。
GroupJoin
構文は
from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }
AN復帰IEnumerable<Y>
Yタイプのプロパティからなる匿名型であるParent
とタイプのプロパティをIEnumerable<Child>
。このクエリ構文では、GroupJoin
内部でメソッドを使用します。
select g
後者のクエリIEnumerable<IEnumerable<Child>>
では、リストのリストなどのを選択するだけで実行できます。多くの場合、親を含む選択がより便利です。
言ったように、ステートメント...
from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }
...子グループを持つ親のリストを生成します。これは、2つの小さな追加により、親子ペアのフラットリストに変換できます。
from p in parents
join c in children on p.Id equals c.Id into g // <= into
from c in g.DefaultIfEmpty() // <= flattens the groups
select new { Parent = p.Value, Child = c?.ChildValue }
結果は次のようになります
Value Child
A a1
A a2
A a3
B b1
B b2
C (null)
上記のステートメントでは、範囲変数 c
が再利用されていることに注意してください。これを行うと、既存のステートメントに同等のものを追加join
するだけで、任意のステートメントを単純にに変換できます。outer join
into g from c in g.DefaultIfEmpty()
join
これは、クエリ(または包括的な)構文が優れている点です。メソッド(または流暢)構文は実際に何が起こるかを示しますが、書くのは難しいです:
parents.GroupJoin(children, p => p.Id, c => c.Id, (p, c) => new { p, c })
.SelectMany(x => x.c.DefaultIfEmpty(), (x,c) => new { x.p.Value, c?.ChildValue } )
したがって、outer join
LINQのフラットはGroupJoin
によってフラット化されSelectMany
ます。
親のリストが少し長いと仮定します。一部のUIでは、選択された親のリストがId
値として固定された順序で生成されます。使ってみましょう:
var ids = new[] { 3,7,2,4 };
次に、選択した親をこの正確な順序で親リストからフィルタリングする必要があります。
私たちがするなら...
var result = parents.Where(p => ids.Contains(p.Id));
...の順序parents
によって結果が決まります。親がで並べられているId
場合、結果は親2、3、4、7になります。ただし、join
リストのフィルタリングにも使用できます。そして、ids
最初のリストとして使用することにより、順序は保持されます:
from id in ids
join p in parents on id equals p.Id
select p
結果は親3、7、2、4です。
eduLINQによると:
GroupJoinの機能を理解するための最良の方法は、Joinについて考えることです。そこで、全体的なアイデアは、「外部」入力シーケンスを調べ、「内部」シーケンスから一致するすべてのアイテムを見つけ(各シーケンスのキープロジェクションに基づく)、一致する要素のペアを生成するというものでした。GroupJoinは似ていますが、要素のペアを生成するのではなく、そのアイテムと一致する「内部」アイテムのシーケンスに基づいて、「外部」アイテムごとに1つの結果を生成します。
唯一の違いはreturnステートメントです。
参加:
var lookup = inner.ToLookup(innerKeySelector, comparer);
foreach (var outerElement in outer)
{
var key = outerKeySelector(outerElement);
foreach (var innerElement in lookup[key])
{
yield return resultSelector(outerElement, innerElement);
}
}
GroupJoin:
var lookup = inner.ToLookup(innerKeySelector, comparer);
foreach (var outerElement in outer)
{
var key = outerKeySelector(outerElement);
yield return resultSelector(outerElement, lookup[key]);
}
詳細はこちら: