Definir operações (C#)

As operações de conjunto no LINQ referem-se a operações de consulta que produzem um conjunto de resultados com base 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 System.Collections.Generic.IEnumerable<T> dados. Fontes de dados baseadas em System.Linq.IQueryProvider uso de fontes de dados System.Linq.IQueryable<T> e árvores de expressão. As árvores de expressão têm limitações na sintaxe C# permitida. Além disso, cada IQueryProvider fonte de dados, como o EF Core , pode impor mais restrições. Verifique a documentação da sua fonte de dados.

Nomes de método Descrição Sintaxe da expressão de consulta C# Mais informações
Distinct ou DistinctBy Remove 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 definida, o 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 do conjunto, o que significa 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 do conjunto, o que significa elementos exclusivos 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 strings. A sequência retornada contém os elementos exclusivos da sequência de entrada.

Gráfico mostrando o comportamento 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
 */

Uma abordagem alternativa ao Distinct que requer um keySelector. O keySelector é usado como o discriminador comparativo do tipo de fonte. No código a seguir, as palavras são discriminadas com base em seu Length, e a primeira palavra de cada comprimento é 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.

Gráfico mostrando a ação de Except()

Nota

Os exemplos a seguir neste artigo usam as fontes de dados comuns para essa área.
Cada Student tem um nível de grau, um departamento principal e uma série de classificações. A Teacher também tem uma City propriedade que identifica o campus onde o professor tem aulas. A Department tem um nome, e uma referência a um Teacher que serve como chefe de 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; }
}

Nota

Você pode consultar as fontes de dados comuns para essa área no artigo Visão geral dos operadores de consulta padrão .

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 ExceptBy método é uma abordagem alternativa para Except que toma duas sequências de tipos possivelmente heterogéneos e um keySelector. O tipo do keySelector é igual ao tipo da primeira coleção. Considere a seguinte Teacher matriz e os IDs de professores a excluir. Para encontrar professores na primeira coleção que não estejam na segunda coleção, você pode projetar o 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 C# anterior:

  • A teachers matriz é filtrada apenas para os professores que não estão na teachersToExclude matriz.
  • A teachersToExclude matriz contém o ID valor para 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 tiver um valor de ID correspondente na matriz teachersToExclude é escrito 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.

Gráfico mostrando a intersecção de duas sequências

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 IntersectBy método é uma abordagem alternativa para Intersect que toma duas sequências de tipos possivelmente heterogéneos e um keySelector. O keySelector é usado como o discriminador comparativo do tipo da segunda coleção. Considere as seguintes matrizes de alunos e professores. A consulta correlaciona os itens em cada sequência por nome para encontrar 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 C# anterior:

  • A consulta produz a interseção do Teacher e do Student comparando os nomes.
  • Apenas as pessoas que são encontradas em ambas as matrizes estão presentes na sequência resultante.
  • As instâncias resultantes Student são gravadas na consola.

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 de ambas as sequências de entrada.

Gráfico mostrando a união de duas sequências.

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 UnionBy método é uma abordagem alternativa para Union que toma duas sequências do mesmo tipo e um keySelector. O keySelector é usado como o discriminador comparativo do tipo de fonte. 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 C# anterior:

  • As matrizes teachers e students são tecidas juntas usando os seus nomes como o seletor de chave.
  • Os nomes resultantes são gravados no console.

Consulte também