Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Операции над множествами в LINQ означают запросы, которые создают результирующий набор на основе присутствия или отсутствия эквивалентных элементов в тех же или разных коллекциях.
Внимание
В этих примерах используется System.Collections.Generic.IEnumerable<T> источник данных. Источники данных на основе System.Linq.IQueryProvider используют System.Linq.IQueryable<T> источники данных и деревья выражений. Деревья выражений имеют ограничения на допустимый синтаксис C#. Кроме того, каждый IQueryProvider источник данных, например EF Core , может наложить больше ограничений. Ознакомьтесь с документацией по источнику данных.
| Имена методов | Описание | Синтаксис выражения запроса C# | Дополнительные сведения |
|---|---|---|---|
Distinct или DistinctBy |
Удаляет повторяющиеся значения из коллекции. | Неприменимо. | Enumerable.Distinct Enumerable.DistinctBy Queryable.Distinct Queryable.DistinctBy |
Except или ExceptBy |
Возвращает разность множеств, что означает элементы одной коллекции, которые не присутствуют во второй коллекции. | Неприменимо. | Enumerable.Except Enumerable.ExceptBy Queryable.Except Queryable.ExceptBy |
Intersect или IntersectBy |
Возвращает пересечение множеств, то есть элементы, присутствующие одновременно в обеих коллекциях. | Неприменимо. | Enumerable.Intersect Enumerable.IntersectBy Queryable.Intersect Queryable.IntersectBy |
Union или UnionBy |
Возвращает объединение множеств, т. е. уникальные элементы, присутствующие в одной из двух коллекций. | Неприменимо. | Enumerable.Union Enumerable.UnionBy Queryable.Union Queryable.UnionBy |
Distinct и DistinctBy.
В следующем примере показано поведение метода Enumerable.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
*/
Альтернативным способом вместо Distinct может стать DistinctBy, который принимает keySelector.
keySelector используется как сравнительный дискриминатор для типа источника. В следующем коде слова разделяются на основе их Length, и отображается первое слово каждой длины.
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 и ExceptBy.
В следующем примере показано поведение Enumerable.Except. Возвращаемая последовательность содержит только элементы из первой входной последовательности, которая не входит во вторую входную последовательность.
Примечание.
В следующих примерах в этой статье используются общие источники данных для этой области.
Каждый из них Student имеет уровень оценки, основной отдел и ряд показателей. У него Teacher также есть свойство, указывающее на City кампус, где проводит занятия учитель. У Department есть имя и ссылка на Teacher, который является руководителем отдела.
Пример набора данных можно найти в исходном репозитории.
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
*/
Вместо ExceptBy можно использовать метод Except, который принимает две последовательности потенциально разнородных типов и keySelector. Это keySelector тот же тип, что и тип первой коллекции. Рассмотрим следующий массив Teacher и идентификаторы преподавателей, которых нужно исключить. Чтобы найти преподавателей в первой коллекции, которая не находится во второй коллекции, можно проецировать идентификатор преподавателя на вторую коллекцию:
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}");
}
В приведенном выше коде C#:
- Массив
teachersфильтруется, чтобы включать только тех учителей, которых нет в массивеteachersToExclude. - Массив
teachersToExcludeсодержитIDзначение для всех руководителей отделов. - Вызов
ExceptByприводит к образованию нового набора значений, которые записываются в консоль.
Новый набор значений имеет тип Teacher, который соответствует типу первой коллекции. Каждый teacher в массиве teachers, не имеющий соответствующего значения идентификатора в массиве teachersToExclude, записывается в консоль teachersToExclude.
Intersect и IntersectBy.
В следующем примере показано поведение Enumerable.Intersect. Возвращаемая последовательность содержит элементы, общие для обеих входных последовательностей.
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
*/
Вместо IntersectBy можно использовать метод Intersect, который принимает две последовательности потенциально разнородных типов и keySelector.
keySelector используется как сравнительный дискриминатор для типа второй коллекции. Рассмотрим следующие массивы учащихся и преподавателей. Запрос соответствует элементам в каждой последовательности по имени, чтобы найти тех учащихся, которые также являются преподавателями:
foreach (Student person in
students.IntersectBy(
teachers.Select(t => (t.First, t.Last)), s => (s.FirstName, s.LastName)))
{
Console.WriteLine($"{person.FirstName} {person.LastName}");
}
В приведенном выше коде C#:
- Запрос создает пересечение
TeacherиStudentпосредством сравнения имен. - В результирующей последовательности присутствуют только люди, найденные в обоих массивах.
- Полученные экземпляры
Studentзаписываются в консоль.
Union и UnionBy.
В следующем примере показана операция объединения двух последовательностей строк. Возвращаемая последовательность содержит уникальные элементы из обеих входных последовательностей.
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 можно использовать метод Union, который принимает две последовательности одного типа и keySelector.
keySelector используется как сравнительный дискриминатор для типа источника. Следующий запрос создает список всех людей, которые являются учащимися или преподавателями. Учащиеся, которые также являются учителями, добавляются в набор профсоюзов только один раз:
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}");
}
В приведенном выше коде C#:
-
teachersиstudentsмассивы объединяются, используя их имена в качестве селектора ключей. - Полученные имена записываются в консоль.