Opérations ensemblistes (C#)

Les opérations ensemblistes dans LINQ font référence à des opérations de requête qui produisent un jeu de résultats basé sur la présence ou l’absence d’éléments équivalents dans les mêmes collections ou dans des collections distinctes.

Noms des méthodes Description Syntaxe d'expression de requête C# Plus d’informations
Distinct ou DistinctBy Supprime les valeurs en double d’une collection. Non applicable. Enumerable.Distinct
Enumerable.DistinctBy
Queryable.Distinct
Queryable.DistinctBy
Except ou ExceptBy Retourne la différence ensembliste, à savoir les éléments d’une collection qui n’apparaissent pas dans une seconde collection. Non applicable. Enumerable.Except
Enumerable.ExceptBy
Queryable.Except
Queryable.ExceptBy
Intersect ou IntersectBy Retourne l’intersection ensembliste, à savoir les éléments qui apparaissent dans chacune des deux collections. Non applicable. Enumerable.Intersect
Enumerable.IntersectBy
Queryable.Intersect
Queryable.IntersectBy
Union ou UnionBy Retourne l’union ensembliste, à savoir les éléments uniques qui apparaissent dans l’une ou l’autre des deux collections. Non applicable. Enumerable.Union
Enumerable.UnionBy
Queryable.Union
Queryable.UnionBy

Distinct et DistinctBy

L’exemple suivant illustre le comportement de la méthode Enumerable.Distinct sur une séquence de chaînes. La séquence retournée contient les éléments uniques de la séquence d’entrée.

Graphique illustrant le comportement de 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
 */

DistinctBy est une approche alternative à Distinct qui prend un keySelector. keySelector est utilisé comme discriminateur comparatif du type source. Dans le code suivant, les mots sont discriminés en fonction de leur Length, et le premier mot de chaque longueur est affiché :

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

Except et ExceptBy

L’exemple suivant illustre le comportement de Enumerable.Except. La séquence retournée contient uniquement les éléments de la première séquence d’entrée qui ne figurent pas dans la seconde séquence d’entrée.

Graphique illustrant l’action de Except()

Les exemples suivants de cet article utilisent les sources de données courantes pour ce domaine :

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

Chaque Student a un niveau scolaire, un département principal et une série de notes. Un Teacher a également une propriété City qui identifie le campus où l’enseignant donne des cours. Un Department a un nom, et une référence à un Teacher qui est responsable du département.

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

La méthode ExceptBy est une approche alternative à Except qui prend deux séquences de types potentiellement hétérogènes et un keySelector. Le keySelector est du même type que le type de la première collection. Considérez le tableau Teacher suivant et les ID d’enseignant à exclure. Pour rechercher des enseignants dans la première collection qui ne figurent pas dans la deuxième collection, vous pouvez projeter l’ID de l’enseignant sur la seconde 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}");
}

Dans le code C# précédent :

  • Le tableau teachers est filtré de façon à contenir seulement les enseignants qui ne figurent pas dans le tableau teachersToExclude.
  • Le tableau teachersToExclude contient la valeur de l’ID de tous les responsables de département.
  • L’appel à ExceptBy entraîne un nouvel ensemble de valeurs qui sont écrites dans la console.

Le nouvel ensemble de valeurs est de type Teacher, qui est le type de la première collection. Chaque teacher du tableau teachers qui n’a pas de valeur d’ID correspondante dans le tableau teachersToExclude est écrit sur la console.

Intersect et IntersectBy

L’exemple suivant illustre le comportement de Enumerable.Intersect. La séquence retournée contient les éléments qui sont communs aux deux séquences d’entrée.

Graphique illustrant l’intersection de deux séquences

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

La méthode IntersectBy est une approche alternative à Intersect qui prend deux séquences de types potentiellement hétérogènes et un keySelector. keySelector est utilisé comme discriminateur comparatif du type de la deuxième collection. Considérez les tableaux d’étudiants et d’enseignants suivants. La requête identifie les éléments de chaque séquence par le nom pour trouver les étudiants qui ne sont pas également enseignants :

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

Dans le code C# précédent :

  • La requête produit l’intersection de Teacher et de Student en comparant les noms.
  • Seules les personnes qui se trouvent dans les deux tableaux sont présentes dans la séquence résultante.
  • Les instances Student résultantes sont écrites dans la console.

Union et UnionBy

L’exemple suivant illustre une opération d’union sur deux séquences de chaînes. La séquence retournée contient les éléments uniques des deux séquences d’entrée.

Graphique illustrant l’union de deux séquences.

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

La méthode UnionBy est une approche alternative à Union qui prend deux séquences du même type et un keySelector. keySelector est utilisé comme discriminateur comparatif du type source. La requête suivante produit la liste de toutes les personnes qui sont des étudiants ou des enseignants. Les étudiants qui sont également enseignants sont ajoutés à l’union ensembliste une seule fois :

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

Dans le code C# précédent :

  • Les tableaux teachers et students sont rapprochés en utilisant les noms comme sélecteur de clé.
  • Les noms résultants sont écrits sur la console.

Voir aussi