誰かが何であるか説明してもらえますかGroupJoin()
?
通常とどう違うのJoin()
?
一般的に使用されていますか?
メソッド構文専用ですか?クエリ構文はどうですか?(C#のコード例がいいでしょう)
誰かが何であるか説明してもらえますかGroupJoin()
?
通常とどう違うのJoin()
?
一般的に使用されていますか?
メソッド構文専用ですか?クエリ構文はどうですか?(C#のコード例がいいでしょう)
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
。whileは、結果セットにある:とGroupJoin
同等ですが、関連するエントリの空のリストがあります(SQL結果セットには行があります)。OUTER JOIN
C
C - null
したがって、2つのリストIEnumerable<Parent>
をIEnumerable<Child>
それぞれととします。(Linq toEntitiesの場合:) 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は、タイプの1つのプロパティとタイプのプロパティで構成される匿名タイプ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]);
}
詳細はこちら:
2つの異なるクラスがあるとしましょう。
public class Person
{
public string Name, Email;
public Person(string name, string email)
{
Name = name;
Email = email;
}
}
class Data
{
public string Mail, SlackId;
public Data(string mail, string slackId)
{
Mail = mail;
SlackId = slackId;
}
}
それでは、使用するデータを準備しましょう。
var people = new Person[]
{
new Person("Sudi", "sudi@try.cd"),
new Person("Simba", "simba@try.cd"),
new Person("Sarah", string.Empty)
};
var records = new Data[]
{
new Data("sudi@try.cd", "Sudi_Try"),
new Data("sudi@try.cd", "Sudi@Test"),
new Data("simba@try.cd", "SimbaLion")
};
sudi@try.cdには2つのslackIdがあることに気付くでしょう。これは、Joinがどのように機能するかを示すために作成しました。
次に、PersonとDataを結合するクエリを作成しましょう。
var query = people.Join(records,
x => x.Email,
y => y.Mail,
(person, record) => new { Name = person.Name, SlackId = record.SlackId});
Console.WriteLine(query);
クエリを作成した後、次のようにforeachを使用してクエリを繰り返すこともできます。
foreach (var item in query)
{
Console.WriteLine($"{item.Name} has Slack ID {item.SlackId}");
}
GroupJoinの結果も出力しましょう。
Console.WriteLine(
people.GroupJoin(
records,
x => x.Email,
y => y.Mail,
(person, recs) => new {
Name = person.Name,
SlackIds = recs.Select(r => r.SlackId).ToArray() // You could materialize //whatever way you want.
}
));
GroupJoinがすべてのSlackIdを単一のグループに配置することに気付くでしょう。