首頁 >後端開發 >C++ >如何在LINQ中執行完整的外部連接?

如何在LINQ中執行完整的外部連接?

Patricia Arquette
Patricia Arquette原創
2025-01-31 17:21:13748瀏覽

How to Perform a Full Outer Join in LINQ?

LINQ - 全外連接

問題:

如何基於公共鍵字段在兩個對象列表之間執行全外連接,確保兩個列表中的所有記錄都包含在結果中,即使它們在另一個列表中沒有對應的匹配項?

答案:

1. 全外連接的自定義擴展方法

為了在 LINQ 中實現全外連接,我們可以定義一個自定義擴展方法,如下所示:

<code class="language-csharp">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;
}</code>

2. 實現

在提供的示例中,我們有兩個列表:firstNameslastNames。要執行全外連接,我們可以使用以下代碼:

<code class="language-csharp">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
                };</code>

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