首页 > 后端开发 > C++ > 如何在LINQ中执行完整的外部连接?

如何在LINQ中执行完整的外部连接?

Patricia Arquette
发布: 2025-01-31 17:21:13
原创
828 人浏览过

How to Perform a Full Outer Join in LINQ?

LINQ - 全外连接

问题:

如何基于公共键字段在两个对象列表之间执行全外连接,确保两个列表中的所有记录都包含在结果中,即使它们在另一个列表中没有对应的匹配项?

答案:

1. 全外连接的自定义扩展方法

为了在 LINQ 中实现全外连接,我们可以定义一个自定义扩展方法,如下所示:

public static IEnumerable<TResult> FullOuterJoin<TA, TB, TKey, TResult>(
    this IEnumerable<TA> a,
    IEnumerable<TB> b,
    Func<TA, TKey> selectKeyA,
    Func<TB, TKey> selectKeyB,
    Func<TA, TB, TKey, TResult> projection,
    TA defaultA = default(TA),
    TB defaultB = default(TB),
    IEqualityComparer<TKey> cmp = null)
{
    cmp = cmp ?? EqualityComparer<TKey>.Default;
    var alookup = a.ToLookup(selectKeyA, cmp);
    var blookup = b.ToLookup(selectKeyB, cmp);

    var keys = new HashSet<TKey>(alookup.Select(p => p.Key), cmp);
    keys.UnionWith(blookup.Select(p => p.Key));

    var join = from key in keys
               from xa in alookup[key].DefaultIfEmpty(defaultA)
               from xb in blookup[key].DefaultIfEmpty(defaultB)
               select projection(xa, xb, key);

    return join;
}
登录后复制

2. 实现

在提供的示例中,我们有两个列表:firstNameslastNames。要执行全外连接,我们可以使用以下代码:

var outerJoin = from first in firstNames
                join last in lastNames
                on first.ID equals last.ID
                into temp
                from last in temp.DefaultIfEmpty()
                select new
                {
                    id = first != null ? first.ID : last.ID,
                    firstname = first != null ? first.Name : string.Empty,
                    surname = last != null ? last.Name : string.Empty
                };
登录后复制

3. 解释

此代码使用左外连接,其中 firstNames 中的每条记录都与 lastNames 中的第一条匹配记录连接,如果找不到匹配项,则连接到默认值。into temp 语句创建了一个 lastNames 中匹配记录的临时集合,允许我们应用 DefaultIfEmpty() 以确保包含不匹配的记录。 这实际上实现了左外连接,并非完整意义上的全外连接。 要实现全外连接,需要使用上面自定义的FullOuterJoin扩展方法。

4. 预期输出

全外连接的预期输出为:

<code>ID  FirstName  LastName
--  ---------  --------
1   John       Doe
2   Sue        
3             Smith</code>
登录后复制

5. 可自定义的默认值

提供的扩展方法允许您为不匹配的记录指定默认值。在示例中,我们为不匹配的名称指定了 string.Empty,为不匹配的 ID 指定了负整数。

6. 性能注意事项

全外连接的运行时间为 O(n m),其中 n 和 m 是两个输入列表的长度。这是因为 ToLookup() 操作需要 O(n) 时间,后续操作需要 O(n m) 时间。

7. LINQ 实现

全外连接的这种实现目前不是 LINQ 标准的一部分,但已建议将其包含在未来的版本中。 标准LINQ不直接支持全外连接,需要自定义扩展方法来实现。

以上是如何在LINQ中执行完整的外部连接?的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板