219

誰かが何であるか説明してもらえますかGroupJoin()

通常とどう違うのJoin()

一般的に使用されていますか?

メソッド構文専用ですか?クエリ構文はどうですか?(C#のコード例がいいでしょう)

4

3 に答える 3

429

行動

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 JOINCC - 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>>、たとえばリストのリストを選択するだけで済みます。多くの場合、親を含む選択の方が便利です。

いくつかのユースケース

1.フラットアウタージョインを作成します。

言ったように、ステートメント...

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 joininto 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 joinLINQのフラットは、GroupJoinによってフラット化されSelectManyます。

2.順序を維持する

親のリストが少し長いと仮定します。一部の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です。

于 2013-03-24T13:40:25.783 に答える
21

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]); 
} 

詳細はこちら:

于 2013-03-24T10:06:00.410 に答える
1

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を単一のグループに配置することに気付くでしょう。

于 2020-11-13T02:06:20.460 に答える