Operaciones set [C#]
Las operaciones Set de LINQ se refieren a operaciones de consulta que generan un conjunto de resultados en función de la presencia o ausencia de elementos equivalentes dentro de la misma colección o en distintas colecciones.
Importante
Estos ejemplos usan un origen de datos System.Collections.Generic.IEnumerable<T>. Los orígenes de datos basados en System.Linq.IQueryProvider usanSystem.Linq.IQueryable<T> orígenes de datos y árboles de expresión . Los árboles de expresión tienen limitaciones en la sintaxis de C# permitida. Además, cada origen de datos IQueryProvider
, como EF Core puede imponer más restricciones. Compruebe la documentación del origen de datos.
Nombres de método | Descripción | Sintaxis de la expresión de consulta de C# | Más información |
---|---|---|---|
Distinct o DistinctBy |
Quita valores duplicados de una colección. | No aplicable. | Enumerable.Distinct Enumerable.DistinctBy Queryable.Distinct Queryable.DistinctBy |
Except o ExceptBy |
Devuelve la diferencia de conjuntos, es decir, los elementos de una colección que no aparecen en una segunda colección. | No aplicable. | Enumerable.Except Enumerable.ExceptBy Queryable.Except Queryable.ExceptBy |
Intersect o IntersectBy |
Devuelve la intersección de conjuntos, es decir, los elementos que aparecen en las dos colecciones. | No aplicable. | Enumerable.Intersect Enumerable.IntersectBy Queryable.Intersect Queryable.IntersectBy |
Union o UnionBy |
Devuelve la unión de conjuntos, es decir, los elementos únicos que aparecen en una de las dos colecciones. | No es aplicable. | Enumerable.Union Enumerable.UnionBy Queryable.Union Queryable.UnionBy |
Distinct
y DistinctBy
En la siguiente ilustración se muestra el comportamiento del método Enumerable.Distinct en una secuencia de cadenas. La secuencia devuelta contiene los elementos únicos de la secuencia de entrada.
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
es un enfoque alternativo a Distinct
, que adopta keySelector
. keySelector
se usa como discriminador comparativo del tipo de origen. En el siguiente código, las palabras se discriminan en función de su Length
, y se muestra la primera palabra de cada longitud:
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
y ExceptBy
En el ejemplo siguiente se muestra el comportamiento de Enumerable.Except. La secuencia devuelta solo contiene los elementos de la primera secuencia de entrada que no están en la segunda secuencia de entrada.
Nota:
En los ejemplos siguientes de este artículo se usan los orígenes de datos comunes para esta área.
Cada Student
tiene un nivel académico, un departamento principal y una serie de puntuaciones. Un Teacher
también tiene una propiedad City
que identifica el campus donde el profesor imparte clases. Un Department
tiene un nombre y una referencia a un Teacher
que actúa como jefe del departamento.
Puede encontrar el conjunto de datos de ejemplo en el repositorio de origen.
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
*/
El método ExceptBy es un enfoque alternativo a Except
que adopta dos secuencias de tipos posiblemente heterogéneos y keySelector
. El keySelector
es el mismo tipo que el tipo de la primera colección. Tenga en cuenta la siguiente matriz Teacher
e identificadores de profesor que se van a excluir. Para buscar profesores en la primera colección que no están en la segunda, puede proyectar el identificador de profesor en la segunda colección:
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}");
}
En el código de C# anterior:
- La matriz
teachers
se filtra solo a los profesores que no están en la matrizteachersToExclude
. - La matriz
teachersToExclude
contiene el valorID
de todos los jefes de departamento. - La llamada a
ExceptBy
da como resultado un nuevo conjunto de valores que se escriben en la consola.
El nuevo conjunto de valores es de tipo Teacher
, que es el tipo de la primera colección. Cada teacher
de la matriz teachers
que no tiene un valor de identificador correspondiente en la matriz teachersToExclude
se escribe en la consola.
Intersect
y IntersectBy
En el ejemplo siguiente se muestra el comportamiento de Enumerable.Intersect. La secuencia devuelta contiene los elementos que son comunes a las dos secuencias de entrada.
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
*/
El método IntersectBy es un enfoque alternativo a Intersect
que adopta dos secuencias de tipos posiblemente heterogéneos y keySelector
. keySelector
se usa como discriminador comparativo del tipo de la segunda colección. Tenga en cuenta las siguientes matrices de estudiantes y profesores. La consulta coincide con los elementos de cada secuencia por nombre para buscar a los alumnos que también son profesores:
foreach (Student person in
students.IntersectBy(
teachers.Select(t => (t.First, t.Last)), s => (s.FirstName, s.LastName)))
{
Console.WriteLine($"{person.FirstName} {person.LastName}");
}
En el código de C# anterior:
- La consulta genera la intersección de
Teacher
yStudent
comparando nombres. - Solo las personas que se encuentran en ambas matrices están presentes en la secuencia resultante.
- Las instancias
Student
resultantes se escriben en la consola.
Union
y UnionBy
En el siguiente ejemplo se muestra una operación de unión en dos secuencias de cadenas. La secuencia devuelta contiene los elementos únicos de las dos secuencias de entrada.
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 es un enfoque alternativo a Union
que adopta dos secuencias del mismo tipo y keySelector
. keySelector
se usa como discriminador comparativo del tipo de origen. La siguiente consulta genera la lista de todas las personas que son estudiantes o profesores. Los estudiantes que también son profesores se agregan a la unión establecida una sola vez:
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}");
}
En el código de C# anterior:
- Las matrices
teachers
ystudents
se entrelazan con sus nombres como selector de claves. - Los nombres resultantes se escriben en la consola.