ウェブで検索しましたが、まだ簡単な答えが見つかりません。 GroupJoin
が何であるかを(簡単な英語で)誰か説明してもらえますか?通常の内部Join
とどう違うのですか?一般的に使用されていますか?メソッド構文専用ですか?クエリ構文はどうですか? C#のコード例はNiceです。
次の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
はSQLのINNER JOIN
と同等です。C
のエントリはありません。 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 }
IEnumerable<Y>
を返します。Yは、タイプParent
の1つのプロパティとタイプIEnumerable<Child>
のプロパティで構成される匿名タイプです。このクエリ構文は、内部で GroupJoin
メソッドを使用します。
後者のクエリでselect g
を実行するだけで、リストのリストなど、IEnumerable<IEnumerable<Child>>
を選択できます。多くの場合、親が含まれるselectの方が便利です。
述べたように、声明...
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)
range variablec
は上記のステートメントで再利用されることに注意してください。これを行うと、既存のjoin
ステートメントにinto g from c in g.DefaultIfEmpty()
に相当するものを追加することで、join
ステートメントをouter join
に簡単に変換できます。
これは、クエリ(または包括的な)構文が輝く場所です。メソッド(または流fluent)構文は実際に何が起こるかを示しますが、書くのは難しいです:
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 } )
したがって、LINQのフラットなouter join
は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も同様ですが、要素のペアを生成する代わりに、そのアイテムと一致する「内部」アイテムのシーケンスに基づいて、各「外部」アイテムに対して単一の結果を生成します。
唯一の違いは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]);
}
詳細はこちら: