C#idiomatic C#
set-operationscsharp/linq/standard-query-operators

LINQ

Set operations

Learn about set operations and the standard query operator methods that perform set operations in LINQ in C#.

  • page csharp/linq/standard-query-operators/set-operations
  • updated 05/29/2024

Set operations in LINQ refer to query operations that produce a result set based on the presence or absence of equivalent elements within the same or separate collections.


author: BillWagner ms.author: wiwagn ms.topic: include ms.date: 05/29/2024

Method names Description C# query expression syntax More information
Distinct or DistinctBy Removes duplicate values from a collection. Not applicable. System.Linq.Enumerable.Distinct
System.Linq.Enumerable.DistinctBy
System.Linq.Queryable.Distinct
System.Linq.Queryable.DistinctBy
Except or ExceptBy Returns the set difference, which means the elements of one collection that don't appear in a second collection. Not applicable. System.Linq.Enumerable.Except
System.Linq.Enumerable.ExceptBy
System.Linq.Queryable.Except
System.Linq.Queryable.ExceptBy
Intersect or IntersectBy Returns the set intersection, which means elements that appear in each of two collections. Not applicable. System.Linq.Enumerable.Intersect
System.Linq.Enumerable.IntersectBy
System.Linq.Queryable.Intersect
System.Linq.Queryable.IntersectBy
Union or UnionBy Returns the set union, which means unique elements that appear in either of two collections. Not applicable. System.Linq.Enumerable.Union
System.Linq.Enumerable.UnionBy
System.Linq.Queryable.Union
System.Linq.Queryable.UnionBy

Distinct and DistinctBy

The following example depicts the behavior of the System.Linq.Enumerable.Distinct method on a sequence of strings. The returned sequence contains the unique elements from the input sequence.

Graphic showing the behavior of Distinct()

sample · csharpdocs/csharp/linq/standard-query-operators/snippets/standard-query-operators/SetOperations.csDistinct

csharp
namespace StandardQueryOperators;
internal class SetOperations
{
    private static readonly IEnumerable<Teacher> teachers = Sources.Teachers;
    private static readonly IEnumerable<Student> students = Sources.Students;
    public static void RunAllSnippets()
    {
        Console.WriteLine("Distinct");
        Distinct();
        Console.WriteLine("DistinctBy");
        DistinctByExample();
        Console.WriteLine("Except");
        Except();
        Console.WriteLine("ExceptBy");
        ExceptByExample();
        Console.WriteLine("Intersect");
        IntersectInteractive();
        Console.WriteLine("IntersectBy");
        IntersectByExample();
        Console.WriteLine("Union");
        UnionInteractive();
        Console.WriteLine("UnionBy");
        UnionByExample();
    }

    private static void 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
         */
        // </Distinct>
    }

    private static void Except()
    {
        // <Except>
        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
         */
        // </Except>
    }


    private static void DistinctByExample()
    {
        Console.WriteLine("DistinctBy:");

        // <DistinctBy>
        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
        // </DistinctBy>

        Console.WriteLine();
    }

    private static void ExceptByExample()
    {
        Console.WriteLine("ExceptBy:");

        // Teachers except department chairs.

        // <ExceptBy>
        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}");
        }
        // </ExceptBy>

        Console.WriteLine();
    }

    private static void IntersectInteractive()
    {
        // <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
         */
        // </Intersect>
    }

    internal static void IntersectByExample()
    {
        Console.WriteLine("IntersectBy:");

        // Students who are also teachers.

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

        Console.WriteLine();
    }

    private static void UnionInteractive()
    {
        // <Union>
        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
        */
        // </Union>
    }

    private static void UnionByExample()
    {
        Console.WriteLine("UnionBy:");

        // All teachers and students
        // <UnionBy>
        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}");
        }
        // </UnionBy>

        Console.WriteLine();
    }
}

The DistinctBy is an alternative approach to Distinct that takes a keySelector. The keySelector is used as the comparative discriminator of the source type. In the following code, words are discriminated based on their Length, and the first word of each length is displayed:

sampledocs/csharp/linq/standard-query-operators/snippets/standard-query-operators/SetOperations.csDistinctBy

csharp
namespace StandardQueryOperators;
internal class SetOperations
{
    private static readonly IEnumerable<Teacher> teachers = Sources.Teachers;
    private static readonly IEnumerable<Student> students = Sources.Students;
    public static void RunAllSnippets()
    {
        Console.WriteLine("Distinct");
        Distinct();
        Console.WriteLine("DistinctBy");
        DistinctByExample();
        Console.WriteLine("Except");
        Except();
        Console.WriteLine("ExceptBy");
        ExceptByExample();
        Console.WriteLine("Intersect");
        IntersectInteractive();
        Console.WriteLine("IntersectBy");
        IntersectByExample();
        Console.WriteLine("Union");
        UnionInteractive();
        Console.WriteLine("UnionBy");
        UnionByExample();
    }

    private static void 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
         */
        // </Distinct>
    }

    private static void Except()
    {
        // <Except>
        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
         */
        // </Except>
    }


    private static void DistinctByExample()
    {
        Console.WriteLine("DistinctBy:");

        // <DistinctBy>
        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
        // </DistinctBy>

        Console.WriteLine();
    }

    private static void ExceptByExample()
    {
        Console.WriteLine("ExceptBy:");

        // Teachers except department chairs.

        // <ExceptBy>
        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}");
        }
        // </ExceptBy>

        Console.WriteLine();
    }

    private static void IntersectInteractive()
    {
        // <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
         */
        // </Intersect>
    }

    internal static void IntersectByExample()
    {
        Console.WriteLine("IntersectBy:");

        // Students who are also teachers.

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

        Console.WriteLine();
    }

    private static void UnionInteractive()
    {
        // <Union>
        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
        */
        // </Union>
    }

    private static void UnionByExample()
    {
        Console.WriteLine("UnionBy:");

        // All teachers and students
        // <UnionBy>
        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}");
        }
        // </UnionBy>

        Console.WriteLine();
    }
}

Except and ExceptBy

The following example depicts the behavior of System.Linq.Enumerable.Except. The returned sequence contains only the elements from the first input sequence that aren't in the second input sequence.

Graphic showing the action of Except()


author: BillWagner ms.author: wiwagn ms.topic: include ms.date: 10/04/2024

sample · csharpdocs/csharp/linq/standard-query-operators/snippets/standard-query-operators/DataSources.csQueryDataSource

csharp
namespace StandardQueryOperators;

//<QueryDataSource>
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; }
}
// </QueryDataSource>

public static class Sources
{
    public static IEnumerable<Department> Departments =>
    [
        new() { Name = "English",     ID = 1, TeacherID = 901 },
        new() { Name = "Mathematics", ID = 2, TeacherID = 965 },
        new() { Name = "Engineering", ID = 3, TeacherID = 932 },
        new() { Name = "Economics",   ID = 4, TeacherID = 945 },
        new() { Name = "Physics",     ID = 5, TeacherID = 987 },
        new() { Name = "Chemistry",   ID = 6, TeacherID = 901 }
    ];

    // Create a data source by using a collection initializer.
    public static IEnumerable<Student> Students =>
    [
        new() { FirstName = "Svetlana",   LastName = "Omelchenko",  DepartmentID =  1, Year = GradeLevel.FirstYear,  ID = 111, Scores = [97, 90, 73, 54] },
        new() { FirstName = "Claire",     LastName = "O'Donnell",   DepartmentID = -1, Year = GradeLevel.FirstYear,  ID = 112, Scores = [56, 78, 95, 95] },
        new() { FirstName = "Sven",       LastName = "Mortensen",   DepartmentID =  3, Year = GradeLevel.SecondYear, ID = 113, Scores = [61, 52, 48, 72] },
        new() { FirstName = "Cesar",      LastName = "Garcia",      DepartmentID =  4, Year = GradeLevel.SecondYear, ID = 114, Scores = [71, 86, 77, 97] },
        new() { FirstName = "Debra",      LastName = "Garcia",      DepartmentID =  5, Year = GradeLevel.ThirdYear,  ID = 115, Scores = [66, 96, 70, 69] },
        new() { FirstName = "Fadi",       LastName = "Fakhouri",    DepartmentID =  6, Year = GradeLevel.ThirdYear,  ID = 116, Scores = [93, 72, 62, 65] },
        new() { FirstName = "Hanying",    LastName = "Feng",        DepartmentID =  1, Year = GradeLevel.FourthYear, ID = 117, Scores = [53, 81, 81, 50] },
        new() { FirstName = "Hugo",       LastName = "Garcia",      DepartmentID =  2, Year = GradeLevel.FourthYear, ID = 118, Scores = [68, 91, 60, 51] },
        new() { FirstName = "Lance",      LastName = "Tucker",      DepartmentID = -1, Year = GradeLevel.FirstYear,  ID = 119, Scores = [83, 42, 68, 63] },
        new() { FirstName = "Terry",      LastName = "Adams",       DepartmentID =  4, Year = GradeLevel.SecondYear, ID = 120, Scores = [63, 91, 71, 51] },
        new() { FirstName = "Eugene",     LastName = "Zabokritski", DepartmentID =  5, Year = GradeLevel.ThirdYear,  ID = 121, Scores = [56, 40, 73, 75] },
        new() { FirstName = "Michael",    LastName = "Tucker",      DepartmentID =  3, Year = GradeLevel.FourthYear, ID = 122, Scores = [85, 82, 81, 70] },
        new() { FirstName = "Mark",       LastName = "Johansson",   DepartmentID =  1, Year = GradeLevel.FirstYear,  ID = 123, Scores = [82, 94, 84, 65] },
        new() { FirstName = "Sarah",      LastName = "Andersson",   DepartmentID =  1, Year = GradeLevel.FirstYear,  ID = 124, Scores = [77, 83, 67, 90] },
        new() { FirstName = "Christiane", LastName = "Jensen",      DepartmentID =  1, Year = GradeLevel.FirstYear,  ID = 125, Scores = [88, 57, 65, 87] },
        new() { FirstName = "Evgeniya",   LastName = "Maslova",     DepartmentID =  2, Year = GradeLevel.SecondYear, ID = 126, Scores = [46, 84, 87, 66] },
        new() { FirstName = "Innocenty",  LastName = "Popov",       DepartmentID =  6, Year = GradeLevel.SecondYear, ID = 127, Scores = [92, 45, 88, 60] },
        new() { FirstName = "Anna",       LastName = "Hedlund",     DepartmentID =  2, Year = GradeLevel.SecondYear, ID = 128, Scores = [85, 54, 74, 75] },
        new() { FirstName = "Erik",       LastName = "Axelsson",    DepartmentID =  3, Year = GradeLevel.ThirdYear,  ID = 129, Scores = [51, 78, 54, 49] },
        new() { FirstName = "Anna",       LastName = "Yermolayeva", DepartmentID =  3, Year = GradeLevel.ThirdYear,  ID = 130, Scores = [46, 73, 93, 68] },
        new() { FirstName = "Cassie",     LastName = "Hicks",       DepartmentID =  3, Year = GradeLevel.ThirdYear,  ID = 131, Scores = [85, 60, 85, 56] },
        new() { FirstName = "Ifeanacho",  LastName = "Jamuike",     DepartmentID =  4, Year = GradeLevel.FourthYear, ID = 132, Scores = [54, 98, 56, 61] },
        new() { FirstName = "Carmen",     LastName = "Vella",       DepartmentID =  6, Year = GradeLevel.FourthYear, ID = 133, Scores = [63, 57, 69, 70] },
        new() { FirstName = "Noel",       LastName = "Svensson",    DepartmentID =  4, Year = GradeLevel.FourthYear, ID = 134, Scores = [85, 60, 80, 73] },
        new() { FirstName = "Sanna",      LastName = "Hansson",     DepartmentID =  5, Year = GradeLevel.FirstYear,  ID = 135, Scores = [46, 94, 93, 45] },
        new() { FirstName = "Sofiya",     LastName = "Seleznyova",  DepartmentID =  6, Year = GradeLevel.FirstYear,  ID = 136, Scores = [74, 45, 87, 55] },
        new() { FirstName = "Amy E.",     LastName = "Edwards",     DepartmentID =  5, Year = GradeLevel.FirstYear,  ID = 137, Scores = [87, 59, 55, 70] },
        new() { FirstName = "Nancy",      LastName = "Engström",    DepartmentID =  3, Year = GradeLevel.FirstYear,  ID = 138, Scores = [75, 73, 78, 83] },
        new() { FirstName = "Katerina",   LastName = "Kovaleva",    DepartmentID =  2, Year = GradeLevel.FirstYear,  ID = 139, Scores = [44, 50, 47, 41] },
        new() { FirstName = "Ifunanya",   LastName = "Ugomma",      DepartmentID =  4, Year = GradeLevel.FirstYear,  ID = 140, Scores = [84, 82, 96, 80] },
        new() { FirstName = "Don",        LastName = "Richardson",  DepartmentID =  5, Year = GradeLevel.FirstYear,  ID = 141, Scores = [47, 91, 73, 68] },
        new() { FirstName = "Josephine",  LastName = "Balzan",      DepartmentID =  6, Year = GradeLevel.SecondYear, ID = 142, Scores = [40, 47, 63, 42] },
        new() { FirstName = "Michelle",   LastName = "Caruana",     DepartmentID = -1, Year = GradeLevel.FirstYear,  ID = 143, Scores = [97, 92, 69, 77] },
        new() { FirstName = "Gaby",       LastName = "Frost",       DepartmentID =  2, Year = GradeLevel.FirstYear,  ID = 144, Scores = [70, 79, 47, 79] },
        new() { FirstName = "Erna",       LastName = "Nilsson",     DepartmentID =  3, Year = GradeLevel.FirstYear,  ID = 145, Scores = [56, 52, 51, 51] },
        new() { FirstName = "Naima",      LastName = "Larsson",     DepartmentID =  4, Year = GradeLevel.ThirdYear,  ID = 146, Scores = [65, 81, 44, 61] },
        new() { FirstName = "Donald",     LastName = "Urquhart",    DepartmentID =  1, Year = GradeLevel.FirstYear,  ID = 147, Scores = [92, 90, 95, 57] },
        new() { FirstName = "Nadezhda",   LastName = "Kolpakova",   DepartmentID =  1, Year = GradeLevel.FirstYear,  ID = 148, Scores = [94, 69, 52, 58] },
        new() { FirstName = "Ruth",       LastName = "Olsson",      DepartmentID =  2, Year = GradeLevel.FourthYear, ID = 149, Scores = [66, 49, 82, 74] },
        new() { FirstName = "Maria",      LastName = "Sammut",      DepartmentID =  2, Year = GradeLevel.FirstYear,  ID = 150, Scores = [43, 83, 94, 60] },
        new() { FirstName = "Veronika",   LastName = "Berg",        DepartmentID =  3, Year = GradeLevel.FirstYear,  ID = 151, Scores = [59, 76, 65, 92] },
        new() { FirstName = "Nicholas",   LastName = "Micallef",    DepartmentID =  3, Year = GradeLevel.FirstYear,  ID = 152, Scores = [44, 57, 52, 63] },
        new() { FirstName = "Izuchukwu",  LastName = "Adaobi",      DepartmentID =  4, Year = GradeLevel.SecondYear, ID = 153, Scores = [51, 40, 42, 54] },
        new() { FirstName = "Nwanneka",   LastName = "Ifeoma",      DepartmentID =  4, Year = GradeLevel.FirstYear,  ID = 154, Scores = [44, 70, 98, 56] },
        new() { FirstName = "John",       LastName = "Falzon",      DepartmentID =  5, Year = GradeLevel.FirstYear,  ID = 155, Scores = [77, 65, 83, 45] },
        new() { FirstName = "Martina",    LastName = "Mattsson",    DepartmentID =  5, Year = GradeLevel.ThirdYear,  ID = 156, Scores = [51, 49, 96, 72] },
        new() { FirstName = "Jeanette",   LastName = "Berggren",    DepartmentID =  4, Year = GradeLevel.FirstYear,  ID = 157, Scores = [41, 67, 46, 68] },
        new() { FirstName = "Anastasiya", LastName = "Sazonova",    DepartmentID =  2, Year = GradeLevel.FirstYear,  ID = 158, Scores = [53, 96, 76, 49] },
        new() { FirstName = "Bruce",      LastName = "Keever",      DepartmentID =  3, Year = GradeLevel.FirstYear,  ID = 159, Scores = [54, 81, 84, 81] },
        new() { FirstName = "Sami",       LastName = "Åkesson",     DepartmentID =  5, Year = GradeLevel.FourthYear, ID = 160, Scores = [45, 85, 79, 94] },
        new() { FirstName = "Jesper",     LastName = "Jakobsson",   DepartmentID =  1, Year = GradeLevel.FirstYear,  ID = 161, Scores = [59, 98, 47, 92] },
        new() { FirstName = "Max",        LastName = "Lindgren",    DepartmentID =  2, Year = GradeLevel.FirstYear,  ID = 162, Scores = [86, 88, 96, 63] },
        new() { FirstName = "Arina",      LastName = "Ivanova",     DepartmentID =  1, Year = GradeLevel.FirstYear,  ID = 163, Scores = [93, 63, 70, 80] }
    ];

    public static IEnumerable<Teacher> Teachers =>
    [
        new() { First = "Ann",       Last = "Beebe",     ID = 901, City = "Seattle" },
        new() { First = "Alex",      Last = "Robinson",  ID = 910, City = "Redmond" },
        new() { First = "Michiyo",   Last = "Sato",      ID = 921, City = "Tacoma"  },
        new() { First = "Aylin",     Last = "Lundgren",  ID = 932, City = "Seattle" },
        new() { First = "Gleb",      Last = "Seleznyov", ID = 943, City = "Redmond" },
        new() { First = "Alexandra", Last = "Voronova",  ID = 954, City = "Tacoma" },
        new() { First = "Kevin",     Last = "McDowell",  ID = 965, City = "Redmond" },
        new() { First = "Selma",     Last = "Nyberg",    ID = 976, City = "Seattle" },
        new() { First = "Selma",     Last = "Åstrom",    ID = 987, City = "Redmond" },
        new() { First = "Hillevi",   Last = "Bengtsson", ID = 998, City = "Tacoma" },
        new() { First = "Allan",     Last = "Sandberg",  ID = 912, City = "Seattle" },
        new() { First = "Dmitry",    Last = "Degtyarev", ID = 923, City = "Redmond" },
        new() { First = "Arinze",    Last = "Madu",      ID = 934, City = "Seattle" },
        new() { First = "Andrey",    Last = "Glazkov",   ID = 945, City = "Redmond" },
        new() { First = "Kettil",    Last = "Berggren",  ID = 956, City = "Tacoma" },
        new() { First = "Hanying",   Last = "Feng",      ID = 967, City = "Seattle" },
        new() { First = "Hugo",      Last = "Garcia",    ID = 978, City = "Redmond" },
        new() { First = "Michael",   Last = "Tucker",    ID = 989, City = "Tacoma" },
        new() { First = "Ifeanacho", Last = "Jamuike",   ID = 991, City = "Redmond" },
        new() { First = "Carmen",    Last = "Vella",     ID = 982, City = "Tacoma" },
        new() { First = "Noel",      Last = "Svensson",  ID = 973, City = "Seattle" }
   ];
}

author: '' ms.author: '' ms.topic: include ms.date: 08/11/2025

sample · csharpdocs/csharp/linq/standard-query-operators/snippets/standard-query-operators/SetOperations.csExcept

csharp
namespace StandardQueryOperators;
internal class SetOperations
{
    private static readonly IEnumerable<Teacher> teachers = Sources.Teachers;
    private static readonly IEnumerable<Student> students = Sources.Students;
    public static void RunAllSnippets()
    {
        Console.WriteLine("Distinct");
        Distinct();
        Console.WriteLine("DistinctBy");
        DistinctByExample();
        Console.WriteLine("Except");
        Except();
        Console.WriteLine("ExceptBy");
        ExceptByExample();
        Console.WriteLine("Intersect");
        IntersectInteractive();
        Console.WriteLine("IntersectBy");
        IntersectByExample();
        Console.WriteLine("Union");
        UnionInteractive();
        Console.WriteLine("UnionBy");
        UnionByExample();
    }

    private static void 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
         */
        // </Distinct>
    }

    private static void Except()
    {
        // <Except>
        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
         */
        // </Except>
    }


    private static void DistinctByExample()
    {
        Console.WriteLine("DistinctBy:");

        // <DistinctBy>
        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
        // </DistinctBy>

        Console.WriteLine();
    }

    private static void ExceptByExample()
    {
        Console.WriteLine("ExceptBy:");

        // Teachers except department chairs.

        // <ExceptBy>
        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}");
        }
        // </ExceptBy>

        Console.WriteLine();
    }

    private static void IntersectInteractive()
    {
        // <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
         */
        // </Intersect>
    }

    internal static void IntersectByExample()
    {
        Console.WriteLine("IntersectBy:");

        // Students who are also teachers.

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

        Console.WriteLine();
    }

    private static void UnionInteractive()
    {
        // <Union>
        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
        */
        // </Union>
    }

    private static void UnionByExample()
    {
        Console.WriteLine("UnionBy:");

        // All teachers and students
        // <UnionBy>
        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}");
        }
        // </UnionBy>

        Console.WriteLine();
    }
}

The System.Linq.Enumerable.ExceptBy method is an alternative approach to Except that takes two sequences of possibly heterogenous types and a keySelector. The keySelector is the same type as the first collection's type. Consider the following Teacher array and teacher IDs to exclude. To find teachers in the first collection that aren't in the second collection, you can project the teacher's ID onto the second collection:

sample · csharpdocs/csharp/linq/standard-query-operators/snippets/standard-query-operators/SetOperations.csExceptBy

csharp
namespace StandardQueryOperators;
internal class SetOperations
{
    private static readonly IEnumerable<Teacher> teachers = Sources.Teachers;
    private static readonly IEnumerable<Student> students = Sources.Students;
    public static void RunAllSnippets()
    {
        Console.WriteLine("Distinct");
        Distinct();
        Console.WriteLine("DistinctBy");
        DistinctByExample();
        Console.WriteLine("Except");
        Except();
        Console.WriteLine("ExceptBy");
        ExceptByExample();
        Console.WriteLine("Intersect");
        IntersectInteractive();
        Console.WriteLine("IntersectBy");
        IntersectByExample();
        Console.WriteLine("Union");
        UnionInteractive();
        Console.WriteLine("UnionBy");
        UnionByExample();
    }

    private static void 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
         */
        // </Distinct>
    }

    private static void Except()
    {
        // <Except>
        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
         */
        // </Except>
    }


    private static void DistinctByExample()
    {
        Console.WriteLine("DistinctBy:");

        // <DistinctBy>
        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
        // </DistinctBy>

        Console.WriteLine();
    }

    private static void ExceptByExample()
    {
        Console.WriteLine("ExceptBy:");

        // Teachers except department chairs.

        // <ExceptBy>
        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}");
        }
        // </ExceptBy>

        Console.WriteLine();
    }

    private static void IntersectInteractive()
    {
        // <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
         */
        // </Intersect>
    }

    internal static void IntersectByExample()
    {
        Console.WriteLine("IntersectBy:");

        // Students who are also teachers.

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

        Console.WriteLine();
    }

    private static void UnionInteractive()
    {
        // <Union>
        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
        */
        // </Union>
    }

    private static void UnionByExample()
    {
        Console.WriteLine("UnionBy:");

        // All teachers and students
        // <UnionBy>
        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}");
        }
        // </UnionBy>

        Console.WriteLine();
    }
}

In the preceding C# code:

  • The teachers array is filtered to only those teachers that aren't in the teachersToExclude array.
  • The teachersToExclude array contains the ID value for all department heads.
  • The call to ExceptBy results in a new set of values that are written to the console.

The new set of values is of type Teacher, which is the type of the first collection. Each teacher in the teachers array that doesn't have a corresponding ID value in the teachersToExclude array is written to the console.

Intersect and IntersectBy

The following example depicts the behavior of System.Linq.Enumerable.Intersect. The returned sequence contains the elements that are common to both of the input sequences.

Graphic showing the intersection of two sequences

sample · csharpdocs/csharp/linq/standard-query-operators/snippets/standard-query-operators/SetOperations.csIntersect

csharp
namespace StandardQueryOperators;
internal class SetOperations
{
    private static readonly IEnumerable<Teacher> teachers = Sources.Teachers;
    private static readonly IEnumerable<Student> students = Sources.Students;
    public static void RunAllSnippets()
    {
        Console.WriteLine("Distinct");
        Distinct();
        Console.WriteLine("DistinctBy");
        DistinctByExample();
        Console.WriteLine("Except");
        Except();
        Console.WriteLine("ExceptBy");
        ExceptByExample();
        Console.WriteLine("Intersect");
        IntersectInteractive();
        Console.WriteLine("IntersectBy");
        IntersectByExample();
        Console.WriteLine("Union");
        UnionInteractive();
        Console.WriteLine("UnionBy");
        UnionByExample();
    }

    private static void 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
         */
        // </Distinct>
    }

    private static void Except()
    {
        // <Except>
        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
         */
        // </Except>
    }


    private static void DistinctByExample()
    {
        Console.WriteLine("DistinctBy:");

        // <DistinctBy>
        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
        // </DistinctBy>

        Console.WriteLine();
    }

    private static void ExceptByExample()
    {
        Console.WriteLine("ExceptBy:");

        // Teachers except department chairs.

        // <ExceptBy>
        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}");
        }
        // </ExceptBy>

        Console.WriteLine();
    }

    private static void IntersectInteractive()
    {
        // <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
         */
        // </Intersect>
    }

    internal static void IntersectByExample()
    {
        Console.WriteLine("IntersectBy:");

        // Students who are also teachers.

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

        Console.WriteLine();
    }

    private static void UnionInteractive()
    {
        // <Union>
        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
        */
        // </Union>
    }

    private static void UnionByExample()
    {
        Console.WriteLine("UnionBy:");

        // All teachers and students
        // <UnionBy>
        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}");
        }
        // </UnionBy>

        Console.WriteLine();
    }
}

The System.Linq.Enumerable.IntersectBy method is an alternative approach to Intersect that takes two sequences of possibly heterogenous types and a keySelector. The keySelector is used as the comparative discriminator of the second collection's type. Consider the following student and teacher arrays. The query matches items in each sequence by name to find those students who are also teachers:

sample · csharpdocs/csharp/linq/standard-query-operators/snippets/standard-query-operators/SetOperations.csIntersectBy

csharp
namespace StandardQueryOperators;
internal class SetOperations
{
    private static readonly IEnumerable<Teacher> teachers = Sources.Teachers;
    private static readonly IEnumerable<Student> students = Sources.Students;
    public static void RunAllSnippets()
    {
        Console.WriteLine("Distinct");
        Distinct();
        Console.WriteLine("DistinctBy");
        DistinctByExample();
        Console.WriteLine("Except");
        Except();
        Console.WriteLine("ExceptBy");
        ExceptByExample();
        Console.WriteLine("Intersect");
        IntersectInteractive();
        Console.WriteLine("IntersectBy");
        IntersectByExample();
        Console.WriteLine("Union");
        UnionInteractive();
        Console.WriteLine("UnionBy");
        UnionByExample();
    }

    private static void 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
         */
        // </Distinct>
    }

    private static void Except()
    {
        // <Except>
        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
         */
        // </Except>
    }


    private static void DistinctByExample()
    {
        Console.WriteLine("DistinctBy:");

        // <DistinctBy>
        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
        // </DistinctBy>

        Console.WriteLine();
    }

    private static void ExceptByExample()
    {
        Console.WriteLine("ExceptBy:");

        // Teachers except department chairs.

        // <ExceptBy>
        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}");
        }
        // </ExceptBy>

        Console.WriteLine();
    }

    private static void IntersectInteractive()
    {
        // <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
         */
        // </Intersect>
    }

    internal static void IntersectByExample()
    {
        Console.WriteLine("IntersectBy:");

        // Students who are also teachers.

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

        Console.WriteLine();
    }

    private static void UnionInteractive()
    {
        // <Union>
        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
        */
        // </Union>
    }

    private static void UnionByExample()
    {
        Console.WriteLine("UnionBy:");

        // All teachers and students
        // <UnionBy>
        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}");
        }
        // </UnionBy>

        Console.WriteLine();
    }
}

In the preceding C# code:

  • The query produces the intersection of the Teacher and Student by comparing names.
  • Only people that are found in both arrays are present in the resulting sequence.
  • The resulting Student instances are written to the console.

Union and UnionBy

The following example depicts a union operation on two sequences of strings. The returned sequence contains the unique elements from both input sequences.

Graphic showing the union of two sequences.

sample · csharpdocs/csharp/linq/standard-query-operators/snippets/standard-query-operators/SetOperations.csUnion

csharp
namespace StandardQueryOperators;
internal class SetOperations
{
    private static readonly IEnumerable<Teacher> teachers = Sources.Teachers;
    private static readonly IEnumerable<Student> students = Sources.Students;
    public static void RunAllSnippets()
    {
        Console.WriteLine("Distinct");
        Distinct();
        Console.WriteLine("DistinctBy");
        DistinctByExample();
        Console.WriteLine("Except");
        Except();
        Console.WriteLine("ExceptBy");
        ExceptByExample();
        Console.WriteLine("Intersect");
        IntersectInteractive();
        Console.WriteLine("IntersectBy");
        IntersectByExample();
        Console.WriteLine("Union");
        UnionInteractive();
        Console.WriteLine("UnionBy");
        UnionByExample();
    }

    private static void 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
         */
        // </Distinct>
    }

    private static void Except()
    {
        // <Except>
        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
         */
        // </Except>
    }


    private static void DistinctByExample()
    {
        Console.WriteLine("DistinctBy:");

        // <DistinctBy>
        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
        // </DistinctBy>

        Console.WriteLine();
    }

    private static void ExceptByExample()
    {
        Console.WriteLine("ExceptBy:");

        // Teachers except department chairs.

        // <ExceptBy>
        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}");
        }
        // </ExceptBy>

        Console.WriteLine();
    }

    private static void IntersectInteractive()
    {
        // <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
         */
        // </Intersect>
    }

    internal static void IntersectByExample()
    {
        Console.WriteLine("IntersectBy:");

        // Students who are also teachers.

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

        Console.WriteLine();
    }

    private static void UnionInteractive()
    {
        // <Union>
        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
        */
        // </Union>
    }

    private static void UnionByExample()
    {
        Console.WriteLine("UnionBy:");

        // All teachers and students
        // <UnionBy>
        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}");
        }
        // </UnionBy>

        Console.WriteLine();
    }
}

The System.Linq.Enumerable.UnionBy method is an alternative approach to Union that takes two sequences of the same type and a keySelector. The keySelector is used as the comparative discriminator of the source type. The following query produces the list of all people that are either students or teachers. Students who are also teachers are added to the union set only once:

sample · csharpdocs/csharp/linq/standard-query-operators/snippets/standard-query-operators/SetOperations.csUnionBy

csharp
namespace StandardQueryOperators;
internal class SetOperations
{
    private static readonly IEnumerable<Teacher> teachers = Sources.Teachers;
    private static readonly IEnumerable<Student> students = Sources.Students;
    public static void RunAllSnippets()
    {
        Console.WriteLine("Distinct");
        Distinct();
        Console.WriteLine("DistinctBy");
        DistinctByExample();
        Console.WriteLine("Except");
        Except();
        Console.WriteLine("ExceptBy");
        ExceptByExample();
        Console.WriteLine("Intersect");
        IntersectInteractive();
        Console.WriteLine("IntersectBy");
        IntersectByExample();
        Console.WriteLine("Union");
        UnionInteractive();
        Console.WriteLine("UnionBy");
        UnionByExample();
    }

    private static void 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
         */
        // </Distinct>
    }

    private static void Except()
    {
        // <Except>
        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
         */
        // </Except>
    }


    private static void DistinctByExample()
    {
        Console.WriteLine("DistinctBy:");

        // <DistinctBy>
        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
        // </DistinctBy>

        Console.WriteLine();
    }

    private static void ExceptByExample()
    {
        Console.WriteLine("ExceptBy:");

        // Teachers except department chairs.

        // <ExceptBy>
        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}");
        }
        // </ExceptBy>

        Console.WriteLine();
    }

    private static void IntersectInteractive()
    {
        // <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
         */
        // </Intersect>
    }

    internal static void IntersectByExample()
    {
        Console.WriteLine("IntersectBy:");

        // Students who are also teachers.

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

        Console.WriteLine();
    }

    private static void UnionInteractive()
    {
        // <Union>
        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
        */
        // </Union>
    }

    private static void UnionByExample()
    {
        Console.WriteLine("UnionBy:");

        // All teachers and students
        // <UnionBy>
        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}");
        }
        // </UnionBy>

        Console.WriteLine();
    }
}

In the preceding C# code:

  • The teachers and students arrays are woven together using their names as the key selector.
  • The resulting names are written to the console.

See also