Operazioni set (C#)
Le operazioni set in LINQ si riferiscono alle operazioni di query che producono un set di risultati in base alla presenza o all'assenza di elementi equivalenti all'interno della stessa raccolta o di raccolte separate.
Importante
In questi esempi viene usata un'origine dati System.Collections.Generic.IEnumerable<T>. Le origini dati basate su System.Linq.IQueryProvider usano origini dati System.Linq.IQueryable<T> e alberi delle espressioni. La sintassi consentita per gli alberi delle espressioni presenta limitazioni. Inoltre, ogni origine dati IQueryProvider
, ad esempio EF Core può imporre altre restrizioni. Consultare la documentazione relativa all'origine dati.
Nomi dei metodi | Descrizione | Sintassi dell'espressione di query C# | Ulteriori informazioni |
---|---|---|---|
Distinct oppure DistinctBy |
Rimuove i valori duplicati da una Collection. | Non applicabile. | Enumerable.Distinct Enumerable.DistinctBy Queryable.Distinct Queryable.DistinctBy |
Except oppure ExceptBy |
Restituisce la differenza dei set, ovvero gli elementi di una raccolta che non compaiono in una seconda raccolta. | Non applicabile. | Enumerable.Except Enumerable.ExceptBy Queryable.Except Queryable.ExceptBy |
Intersect oppure IntersectBy |
Restituisce l'intersezione di set, ovvero gli elementi presenti in ognuna delle due Collection. | Non applicabile. | Enumerable.Intersect Enumerable.IntersectBy Queryable.Intersect Queryable.IntersectBy |
Union oppure UnionBy |
Restituisce l'unione di set, ovvero gli elementi univoci presenti in una delle due Collection. | Non applicabile. | Enumerable.Union Enumerable.UnionBy Queryable.Union Queryable.UnionBy |
Distinct
e DistinctBy
L'esempio seguente mostra il comportamento del metodo Enumerable.Distinct su una sequenza di stringhe. La sequenza restituita contiene gli elementi univoci dalla sequenza di input.
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
è un approccio alternativo a Distinct
che accetta un keySelector
. keySelector
viene utilizzato come discriminante comparativo del tipo di origine. Nel seguente codice, le parole vengono discriminate in base al relativo Length
e viene visualizzata la prima parola di ogni lunghezza:
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
e ExceptBy
L'esempio seguente mostra il comportamento di Enumerable.Except. La sequenza restituita contiene solo gli elementi della prima sequenza di input che non sono presenti nella seconda sequenza di input.
Nota
Gli esempi seguenti in questo articolo usano le origini dati comuni per questa area.
Ogni Student
ha un livello di classe, un reparto primario e una serie di punteggi. Un Teacher
ha anche una proprietà City
che identifica il campus in cui l'insegnante tiene le lezioni. Un Department
ha un nome e un riferimento a un Teacher
che funge da responsabile del reparto.
È possibile trovare il set di dati di esempio nel repository di origine.
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; }
}
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
*/
Il metodo ExceptBy è un approccio alternativo a Except
che accetta due sequenze di tipi possibilmente eterogenei e un keySelector
. keySelector
è lo stesso tipo di quello della prima raccolta. Si consideri il seguente array Teacher
e gli ID insegnante da escludere. Per trovare insegnanti della prima raccolta che non sono presenti nella seconda raccolta, è possibile proiettare l'ID dell'insegnante sulla seconda raccolta:
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}");
}
Nel codice C# precedente:
- L'array
teachers
viene filtrato solo per gli insegnanti che non sono presenti nell'arrayteachersToExclude
. - L'array
teachersToExclude
contiene il valoreID
per tutti i responsabili del reparto. - La chiamata a
ExceptBy
produce un nuovo set di valori che vengono scritti nella console.
Il nuovo set di valori è di tipo Teacher
, che è il tipo della prima raccolta. Ogni teacher
nell'array teachers
che non ha un valore ID corrispondente nell'array teachersToExclude
viene scritto nella console.
Intersect
e IntersectBy
L'esempio seguente mostra il comportamento di Enumerable.Intersect. La sequenza restituita contiene gli elementi comuni a entrambe le sequenze di input.
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
*/
Il metodo IntersectBy è un approccio alternativo a Intersect
che accetta due sequenze di tipi possibilmente eterogenei e un keySelector
. keySelector
viene utilizzato come discriminante comparativo del tipo della seconda raccolta. Si considerino i seguenti array di studenti e insegnanti. La query corrisponde agli elementi in ogni sequenza in base al nome per trovare gli studenti che sono anche insegnanti:
foreach (Student person in
students.IntersectBy(
teachers.Select(t => (t.First, t.Last)), s => (s.FirstName, s.LastName)))
{
Console.WriteLine($"{person.FirstName} {person.LastName}");
}
Nel codice C# precedente:
- La query produce l'intersezione di
Teacher
eStudent
confrontando i nomi. - Solo le persone che si trovano in entrambi gli array sono presenti nella sequenza risultante.
- Le istanze risultanti
Student
vengono scritte nella console.
Union
e UnionBy
L'esempio seguente mostra un'operazione di unione su due sequenze di stringhe. La sequenza restituita contiene gli elementi univoci da entrambe le sequenze di input.
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
*/
Il metodo UnionBy è un approccio alternativo a Union
che accetta due sequenze dello stesso tipo e un keySelector
. keySelector
viene utilizzato come discriminante comparativo del tipo di origine. La query seguente produce l'elenco di tutte le persone che sono studenti o insegnanti. Gli studenti che sono anche insegnanti vengono aggiunti al set di unione una sola volta:
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}");
}
Nel codice C# precedente:
- Gli array
teachers
estudents
vengono uniti insieme usando i loro nomi come selettore a chiave. - I nomi risultanti vengono scritti nella console.