Operações de conjunto (C#)
Definir operações no LINQ referem-se a operações de consulta que produzem um conjunto de resultados baseado na presença ou ausência de elementos equivalentes dentro das mesmas coleções ou coleções separadas.
Importante
Esses exemplos usam uma fonte de dados System.Collections.Generic.IEnumerable<T>. Fontes de dados baseadas em System.Linq.IQueryProvider usam as fontes de dados System.Linq.IQueryable<T> e as árvores de expressão. As árvores de expressão possuem limitações na sintaxe C# permitida. Além disso, todas as fontes de dados IQueryProvider
, como EF Core, podem impor mais restrições. Verifique a documentação da fonte de dados.
Nomes de método | Descrição | Sintaxe de expressão de consulta em C# | Mais informações |
---|---|---|---|
Distinct ou DistinctBy |
Remove os valores duplicados de uma coleção. | Não aplicável. | Enumerable.Distinct Enumerable.DistinctBy Queryable.Distinct Queryable.DistinctBy |
Except ou ExceptBy |
Retorna a diferença de conjunto, que significa os elementos de uma coleção que não aparecem em uma segunda coleção. | Não aplicável. | Enumerable.Except Enumerable.ExceptBy Queryable.Except Queryable.ExceptBy |
Intersect ou IntersectBy |
Retorna a interseção de conjunto, o que significa os elementos que aparecem em cada uma das duas coleções. | Não aplicável. | Enumerable.Intersect Enumerable.IntersectBy Queryable.Intersect Queryable.IntersectBy |
Union ou UnionBy |
Retorna a união de conjunto, o que significa os elementos únicos que aparecem em qualquer uma das duas coleções. | Não aplicável. | Enumerable.Union Enumerable.UnionBy Queryable.Union Queryable.UnionBy |
Distinct
e DistinctBy
O exemplo a seguir descreve o comportamento do método Enumerable.Distinct em uma sequência de cadeias de caracteres. A sequência retornada contém os elementos exclusivos da sequência 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
é uma abordagem alternativa a Distinct
que usa keySelector
. keySelector
é usado como o discriminador comparativo do tipo de origem. No seguinte código, as palavras são discriminados com base no respectivo Length
, e a primeira palavra de cada tipo é exibida:
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
O exemplo a seguir descreve o comportamento de Enumerable.Except. A sequência retornada contém apenas os elementos da primeira sequência de entrada que não estão na segunda sequência de entrada.
Observação
Os exemplos a seguir neste artigo usam as fontes de dados comuns para essa área.
Cada Student
tem um nível de escolaridade, um departamento primário e uma série de pontuações. Um Teacher
também tem uma propriedade City
que identifica o campus onde o docente ministra aulas. A Department
tem um nome e uma referência a um Teacher
que atua como chefe do departamento.
Você pode encontrar o conjunto de dados de exemplo no repositório de origem.
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
*/
O método ExceptBy é uma abordagem alternativa a Except
que usa duas sequências de tipos possivelmente heterogêneos e um keySelector
. O keySelector
é o mesmo tipo que o tipo da primeira coleção. Considere a matriz Teacher
a seguir e IDs de professor a serem excluídas. Para encontrar professores na primeira coleção que não estão na segunda coleção, você pode projetar a ID do professor na segunda coleção:
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}");
}
No código anterior do C#:
- A matriz
teachers
é filtrada apenas para os professores que não estão na matrizteachersToExclude
. - A matriz
teachersToExclude
contém o valorID
de todos os chefes de departamento. - A chamada para
ExceptBy
resulta em um novo conjunto de valores que são gravados no console.
O novo conjunto de valores é do tipo Teacher
, que é o tipo da primeira coleção. Cada teacher
na matriz teachers
que não tem um valor de ID correspondente na matriz teachersToExclude
é gravada no console.
Intersect
e IntersectBy
O exemplo a seguir descreve o comportamento de Enumerable.Intersect. A sequência retornada contém os elementos que são comuns a ambas as sequências 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
*/
O método IntersectBy é uma abordagem alternativa a Intersect
que usa duas sequências de tipos possivelmente heterogêneos e um keySelector
. O keySelector
é usado como o discriminatório comparativo do tipo da segunda coleção. Considere as matrizes de alunos e professores a seguir. A consulta corresponde aos itens em cada sequência por nome para localizar os alunos que também são professores:
foreach (Student person in
students.IntersectBy(
teachers.Select(t => (t.First, t.Last)), s => (s.FirstName, s.LastName)))
{
Console.WriteLine($"{person.FirstName} {person.LastName}");
}
No código anterior do C#:
- A consulta produz a interseção do
Teacher
eStudent
comparando nomes. - Somente as pessoas encontradas em ambas as matrizes estão presentes na sequência resultante.
- As instâncias resultantes
Student
são gravadas no console.
Union
e UnionBy
O exemplo a seguir descreve uma operação de união em duas sequências de cadeias de caracteres. A sequência retornada contém os elementos exclusivos das duas sequências 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
*/
O método UnionBy é uma abordagem alternativa a Union
que usa duas sequências do mesmo tipo e uma keySelector
. keySelector
é usado como o discriminador comparativo do tipo de origem. A consulta a seguir produz a lista de todas as pessoas que são alunos ou professores. Os alunos que também são professores são adicionados ao conjunto sindical apenas uma 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}");
}
No código anterior do C#:
- As matrizes
teachers
estudents
são tecidas usando os nomes delas como o seletor de chaves. - OS nomes resultantes são gravados no console.