設定作業 (C#)

LINQ 中的設定作業指的是產生結果集的查詢作業,而結果集是根據相同或不同集合內是否有對等項目而定。

方法名稱 描述 C# 查詢運算式語法 其他相關資訊
DistinctDistinctBy 移除集合中的重複值。 不適用。 Enumerable.Distinct
Enumerable.DistinctBy
Queryable.Distinct
Queryable.DistinctBy
ExceptExceptBy 傳回集差異,表示未出現在第二個集合中的某個集合中的項目。 不適用。 Enumerable.Except
Enumerable.ExceptBy
Queryable.Except
Queryable.ExceptBy
IntersectIntersectBy 傳回集交集,表示出現在這兩個集合中的項目。 不適用。 Enumerable.Intersect
Enumerable.IntersectBy
Queryable.Intersect
Queryable.IntersectBy
UnionUnionBy 傳回集聯集,表示出現在兩個集合中任一集合的唯一項目。 不適用。 Enumerable.Union
Enumerable.UnionBy
Queryable.Union
Queryable.UnionBy

DistinctDistinctBy

下列範例說明一系列字串的 Enumerable.Distinct 方法行為。 所傳回的序列包含輸入序列中的唯一項目。

顯示 Distinct() 行為的圖形

string[] words = ["the", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog"];

IEnumerable<string> query = from word in words.Distinct()
                            select word;

foreach (var str in query)
{
    Console.WriteLine(str);
}

/* This code produces the following output:
 *
 * the
 * quick
 * brown
 * fox
 * jumped
 * over
 * lazy
 * dog
 */

DistinctByDistinct 的替代方法,其採用 keySelectorkeySelector 作為來源類型的比較鑑別子。 在下列程式碼中,會根據 Length 區分字詞,並顯示每個長度的第一個字詞:

string[] words = ["the", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog"];

foreach (string word in words.DistinctBy(p => p.Length))
{
    Console.WriteLine(word);
}

// This code produces the following output:
//     the
//     quick
//     jumped
//     over

ExceptExceptBy

下列範例會說明 Enumerable.Except 的行為。 所傳回的序列只包含第一個輸入序列中不在第二個輸入序列中的項目。

顯示 Except() 動作的圖形

本文中的下列範例會使用適用於此區域的通用資料來源:

public enum GradeLevel
{
    FirstYear = 1,
    SecondYear,
    ThirdYear,
    FourthYear
};

public class Student
{
    public required string FirstName { get; init; }
    public required string LastName { get; init; }
    public required int ID { get; init; }

    public required GradeLevel Year { get; init; }
    public required List<int> Scores { get; init; }

    public required int DepartmentID { get; init; }
}

public class Teacher
{
    public required string First { get; init; }
    public required string Last { get; init; }
    public required int ID { get; init; }
    public required string City { get; init; }
}
public class Department
{
    public required string Name { get; init; }
    public int ID { get; init; }

    public required int TeacherID { get; init; }
}

每個 Student 都有一個等級、一個主要部門和一系列分數。 Teacher 也有一個 City 屬性,可識別教師持有課程的校園。 Department 具有名稱,以及擔任部門負責人 Teacher 的參考。

string[] words1 = ["the", "quick", "brown", "fox"];
string[] words2 = ["jumped", "over", "the", "lazy", "dog"];

IEnumerable<string> query = from word in words1.Except(words2)
                            select word;

foreach (var str in query)
{
    Console.WriteLine(str);
}

/* This code produces the following output:
 *
 * quick
 * brown
 * fox
 */

ExceptBy 方法為 Except 的替代方法,其採用兩個可能異質類型的序列和 keySelectorkeySelector 與第一個集合的類型相同。 請考慮排除下列 Teacher 陣列和教師識別碼。 若要在第一個集合中尋找不在第二個集合中的教師,您可以將教師識別碼投影到第二個集合:

int[] teachersToExclude =
[
    901,    // English
    965,    // Mathematics
    932,    // Engineering
    945,    // Economics
    987,    // Physics
    901     // Chemistry
];

foreach (Teacher teacher in
    teachers.ExceptBy(
        teachersToExclude, teacher => teacher.ID))
{
    Console.WriteLine($"{teacher.First} {teacher.Last}");
}

在上述 C# 程式碼中:

  • 陣列 teachers 只會篩選不在 teachersToExclude 陣列中的教師。
  • teachersToExclude 陣列包含所有部門負責人的 ID 值。
  • 呼叫 ExceptBy 會產生寫入主控台的一組新值。

新值的集合類型為 Teacher,這是第一個集合的類型。 teachers 陣列中的每個 teacher 如果在 teachersToExclude 陣列中沒有對應的識別碼值,就會寫入主控台。

IntersectIntersectBy

下列範例會說明 Enumerable.Intersect 的行為。 所傳回的序列包含兩個輸入序列共有的項目。

顯示兩種序列交集的圖形

string[] words1 = ["the", "quick", "brown", "fox"];
string[] words2 = ["jumped", "over", "the", "lazy", "dog"];

IEnumerable<string> query = from word in words1.Intersect(words2)
                            select word;

foreach (var str in query)
{
    Console.WriteLine(str);
}

/* This code produces the following output:
 *
 * the
 */

IntersectBy 方法為 Intersect 的替代方法,其採用兩個可能異質類型的序列和 keySelectorkeySelector 可作為第二個集合類型的比較鑑別子。 請考慮下列學生和教師陣列。 查詢會依名稱比對每個序列中的項目,以尋找不是教師的學生:

foreach (Student person in
    students.IntersectBy(
        teachers.Select(t => (t.First, t.Last)), s => (s.FirstName, s.LastName)))
{
    Console.WriteLine($"{person.FirstName} {person.LastName}");
}

在上述 C# 程式碼中:

  • 查詢會藉由比較名稱來得出 TeacherStudent 的交集。
  • 只有在這兩個陣列中都能找到的人員才會出現在產生的序列中。
  • 產生的 Student 執行個體會寫入主控台。

UnionUnionBy

下列範例說明兩個字串序列的聯合作業。 所傳回的序列包含兩個輸入序列中的唯一項目。

顯示兩個序列聯集的圖形。

string[] words1 = ["the", "quick", "brown", "fox"];
string[] words2 = ["jumped", "over", "the", "lazy", "dog"];

IEnumerable<string> query = from word in words1.Union(words2)
                            select word;

foreach (var str in query)
{
    Console.WriteLine(str);
}

/* This code produces the following output:
 *
 * the
 * quick
 * brown
 * fox
 * jumped
 * over
 * lazy
 * dog
*/

UnionBy 方法為 Union 的替代方法,其採用兩個相同類型序列和 keySelectorkeySelector 作為來源類型的比較鑑別子。 下列查詢會產生學生或教師的所有人員清單。 同樣是教師的學生只能加入到聯合一次:

foreach (var person in
    students.Select(s => (s.FirstName, s.LastName)).UnionBy(
        teachers.Select(t => (FirstName: t.First, LastName: t.Last)), s => (s.FirstName, s.LastName)))
{
    Console.WriteLine($"{person.FirstName} {person.LastName}");
}

在上述 C# 程式碼中:

  • teachersstudents 陣列會使用其名稱作為索引鍵選取器編織在一起。
  • 產生的名稱會寫入主控台。

另請參閱