有人能解释一下GroupJoin()是什么吗?
它与常规的Join()有什么不同
它是常用的吗?
它只适用于方法语法吗?那么查询语法呢?(一个c#代码示例会更好)
发布于 2013-03-24 21:40:26
行为
假设您有两个列表:
Id Value
1 A
2 B
3 C
Id ChildValue
1 a1
1 a2
1 a3
2 b1
2 b2当您在Id字段上Join这两个列表时,结果将是:
Value ChildValue
A a1
A a2
A a3
B b1
B b2当您在Id字段上GroupJoin这两个列表时,结果将是:
Value ChildValues
A [a1, a2, a3]
B [b1, b2]
C []因此,Join会生成父值和子值的平面(表格)结果。
GroupJoin在第一个列表中生成一个条目列表,每个条目在第二个列表中具有一组连接的条目。
这就是为什么Join等同于SQL中的INNER JOIN:没有C条目。而GroupJoin等同于OUTER JOIN:C在结果集中,但是有一个空的相关条目列表(在GroupJoin结果集中应该有一个行C - null)。
语法
因此,让这两个列表分别为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是具有两个属性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类型的属性和一个IEnumerable<Child>类型的属性组成。此查询语法在幕后使用GroupJoin方法。
我们可以在后一个查询中只执行select g,它将选择一个IEnumerable<IEnumerable<Child>>,比如一个列表列表。在许多情况下,包含父级的select更有用。
一些用例
1.生成平面外连接。
如上所述,声明..。
from p in Parent
join c in Child on p.Id equals c.Id into g
select new { Parent = p, Children = g }..。生成具有子组的父组列表。通过添加两个小代码,可以将其转换为父子对的平面列表:
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 } )所以在LINQ中一个扁平的outer join就是一个被SelectMany扁平化的GroupJoin。
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-24 18:06:00
根据eduLINQ的说法
要理解GroupJoin所做的事情,最好的方法就是考虑
。在那里,总体思路是我们查看“外部”输入序列,从“内部”序列中找到所有匹配的项(基于每个序列上的键投影),然后产生匹配元素对。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]);
} 点击此处阅读更多信息:
https://stackoverflow.com/questions/15595289
复制相似问题