Overview

Set operations are query operations that produce a result set that is based on the presence or absence of equivalent elements within the same or separate sets.

Methods

MethodDescriptionQuery expression
Distinct(By)Removes duplicate values from a collectionN/A
Except(By)Returns the elements of one collection that do not appear in the otherN/A
Intersect(By)Elements that appear in each of two collectionsN/A
Union(By)Unique elements that appear in either of two collectionsN/A

The *By methods take a keySelector which is used as the comparative discriminator of the source type.

Distinct and DistinctBy

These methods both take a single collection.

Distinct returns the unique elements in a collection:

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

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

DistinctBy, like all *By methods, takes a keySelector which is used as the comparative discriminator of the source type.

In this example, the first word of each length is displayed:

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

Except and ExceptBy

These methods both take two collections.

Except returns only the elements from the first collection that are not present in the second:

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

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

ExceptBy’s keySelector is of the same type as the first collection’s type.

To find teachers in the first collection that are not in the second collection, project the teacher’s ID onto the second collection:

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

Intersect and IntersectBy

These methods both take two collections.

Intersect returns a collection of elements that are common to both input collections:

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

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

IntersectBy’s keySelector is used as the comparative discriminator of the second collection’s type:

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

Union and UnionBy

These methods both take two collections.

Union returns a collection that contains the unique elements from both input collections:

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

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

UnionBy’s keySelector is used as the comparative discriminator of the source collection’s type:

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